스레드에 바인드 된 TheadLocals를 나열하는 방법이 있습니까? 이상적으로는 Thread.threadLocals 맵에 액세스 할 수 있지만 패키지가 보호되어 있습니다.java : 스레드 로컬리스트?
내가 필요한 이유는 ThreadLocals가 올바르게 정리되었는지 확인하기 위해 스레드 풀에 반환되는 스레드를 검사해야하기 때문입니다. 아마도 이것을 할 수있는 또 다른 방법이 있을까요?
스레드에 바인드 된 TheadLocals를 나열하는 방법이 있습니까? 이상적으로는 Thread.threadLocals 맵에 액세스 할 수 있지만 패키지가 보호되어 있습니다.java : 스레드 로컬리스트?
내가 필요한 이유는 ThreadLocals가 올바르게 정리되었는지 확인하기 위해 스레드 풀에 반환되는 스레드를 검사해야하기 때문입니다. 아마도 이것을 할 수있는 또 다른 방법이 있을까요?
스레드 풀의 afterExecute
메서드를 사용하여 정리하려는 변수를 알고있는 한 어떤 정리 (reinitializiation?)를 수행 할 수 있습니다. 에서 개봉 된 관심 클래스 (들)의 선언 필드를 통해 반복, 스레드 내에서, 그리고 그 유형 각각에 대해이 개체에의 initialValue
에, set
의 ThreadLocal의 인스턴스 -
그렇지 않으면 당신은 반사를 사용할 수 있습니다 (들).
내가 필요로하는 이유는 ThreadLocals이 올바르게 정리되었는지 확인하기 위해 스레드 풀로 반환되는 스레드를 검사해야하기 때문입니다.
개인적으로는 스레드 풀 스레드에서 로컬 스레드 데이터를 사용하는 것이 좋지 않다고 생각합니다. 스레드 로컬 상태가 정말로 필요한 경우 스레드를 자체 관리해야하므로 명시 적으로 데이터를 정리할 수 있습니다.
스레드 풀 스레드의 수명이 불확실하므로 명시 적으로 관리되는 로컬 스레드 데이터에 의존하면 안됩니다.
당신은 당신 자신의 구현에 의해 원래의 Runnable을 감싸는 Runnable 구현을 생성함으로써 AOP와 같은 구조를 사용할 수 있습니다. 그것은 원래 Runnable의 run 메소드를 호출 한 다음 ThreadLocal.remove() 메소드를 호출 할 수 있도록 스레드 컨텍스트 내에서 필요한 다른 정리를 수행합니다. 그런 다음이 래퍼를 스레드 풀에 제공하십시오. 어떤 스레드 풀 구현 (예 : before/afterExecute 메서드가없는 스레드)에서도 작동합니다.
스레드 수명주기에 연결하는 것이 문제가 아닙니다. ThreadPoolExecutor를 사용하고 있으므로 afterExecute 메서드를 사용해야합니다. 문제는 스레드가 주어집니다. 어떻게 스레드 로컬 저장소를 열거합니까? 나는 그것이 비어 있는지 확인하고 싶지 않다면 경고를 남기고 싶다. –
스레드 로컬 사용을 제어 할 수 있습니까? 개발자가 직접 구현을 사용하도록 할 수 있습니까? 목표 달성을 돕기 위해 ThreadLocal을 확장 할 수 있습니다. – Armadillo
소스에서 보면 매우 빡빡합니다. 모든 것은 Thread 또는 ThreadLocal에 대해 비공개입니다.
계기 에이전트를 통해 필요한 작업을 수행하려면 ThreadLocal을 재정 의하여 현재 스레드의 로컬을 덤프 할 메서드를 추가해야합니다. 당신은 방법을 추가 ThreadLocal를 바이트 코드를 패치 BCEL 또는 JavaAssist를 사용해야합니다 http://today.java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html
:
는 여기에 기존 클래스에 로깅을 추가 발견되는 예입니다. 나중에 메서드를 호출 할 수 있도록 리플렉션을 사용하여 메서드에 대한 핸들을 가져와야합니다.
참고 : 제한된 환경 (애플릿 또는 응용 프로그램 서버)에서 실행되는 경우 보안 메커니즘이 일반적으로 시스템 클래스를 망칠 수 없으므로이 기능은 작동하지 않습니다.
Listing ThreadLocals 및 Clearing ThreadLocals은 reflection (및 the setAccessible() flag)을 사용하여 JVM의 일반적인 사용 권한을 무시함으로써 수행 할 수 있습니다. 명백한 이유로, 모든 보안 메커니즘이 제 위치에있는 경우에는 사용할 수 없습니다.
'또 다른 좋은 방법'을 따라, 기존 스레드 로컬의 스냅 샷을 찍은 Runnable 래퍼를 만들고 중첩 된 실행 파일을 실행 한 다음 로컬로있는 모든 스레드를 지우는 (null로 설정) 처음에는 나타나지 않았다.
'스냅 샷'코드를 서브 클래 싱 된 Executor의 beforeExecute() 및 @danben에서 제안한 afterExecute의 '정리'코드에 넣으면 더 잘 수행 할 수 있습니다.
어느 쪽이든, 그 미학은 유지하거나 폐기 할 스레드 로컬을 하드 코딩 할 필요가 없다는 것입니다.
혼란을 피하기 위해 예외 처리가 소스 목록에서 제거되었습니다.
public class ThreadLocalCleaningRunnable implements Runnable
{
private final Runnable runnable;
public ThreadLocalCleaningRunnable(Runnable runnable) {
this.runnable = nonNull(runnable);
}
public void run() {
// printThreadLocals();
Set> initialThreadLocalKeys = getThreadLocalKeys();
try {
runnable.run();
}
finally {
cleanThreadLocalsExcept(initialThreadLocalKeys);
// printThreadLocals();
}
}
public static void printThreadLocals() {
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
String threadName = thread.getName();
for (int i = 0; i > getThreadLocalKeys() {
Thread thread = Thread.currentThread();
Set> threadLocalKeys = new HashSet>();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
for (int i = 0; i) entry).get();
if (o instanceof ThreadLocal) {
threadLocalKeys.add((ThreadLocal) o);
}
}
}
}
}
return threadLocalKeys;
}
public static void cleanThreadLocalsExcept(Set> keptThreadLocalKeys) {
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
for (int i = 0; i) entry).get();
if (o instanceof ThreadLocal) {
ThreadLocal tl = (ThreadLocal) o;
if (!keptThreadLocalKeys.contains(tl)) {
Field valueField = entry.getClass().getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(entry, null);
}
}
}
}
}
}
}
}
동의. 하지만 기존 코드의 버그를 수정하고 다시 설계하지 않으려합니다. –