2010-01-04 5 views
14

스레드에 바인드 된 TheadLocals를 나열하는 방법이 있습니까? 이상적으로는 Thread.threadLocals 맵에 액세스 할 수 있지만 패키지가 보호되어 있습니다.java : 스레드 로컬리스트?

내가 필요한 이유는 ThreadLocals가 올바르게 정리되었는지 확인하기 위해 스레드 풀에 반환되는 스레드를 검사해야하기 때문입니다. 아마도 이것을 할 수있는 또 다른 방법이 있을까요?

답변

2

스레드 풀의 afterExecute 메서드를 사용하여 정리하려는 변수를 알고있는 한 어떤 정리 (reinitializiation?)를 수행 할 수 있습니다. 에서 개봉 된 관심 클래스 (들)의 선언 필드를 통해 반복, 스레드 내에서, 그리고 그 유형 각각에 대해이 개체에의 initialValue에, set의 ThreadLocal의 인스턴스 -

그렇지 않으면 당신은 반사를 사용할 수 있습니다 (들).

1

내가 필요로하는 이유는 ThreadLocals이 올바르게 정리되었는지 확인하기 위해 스레드 풀로 반환되는 스레드를 검사해야하기 때문입니다.

개인적으로는 스레드 풀 스레드에서 로컬 스레드 데이터를 사용하는 것이 좋지 않다고 생각합니다. 스레드 로컬 상태가 정말로 필요한 경우 스레드를 자체 관리해야하므로 명시 적으로 데이터를 정리할 수 있습니다.

스레드 풀 스레드의 수명이 불확실하므로 명시 적으로 관리되는 로컬 스레드 데이터에 의존하면 안됩니다.

+4

동의. 하지만 기존 코드의 버그를 수정하고 다시 설계하지 않으려합니다. –

0

당신은 당신 자신의 구현에 의해 원래의 Runnable을 감싸는 Runnable 구현을 생성함으로써 AOP와 같은 구조를 사용할 수 있습니다. 그것은 원래 Runnable의 run 메소드를 호출 한 다음 ThreadLocal.remove() 메소드를 호출 할 수 있도록 스레드 컨텍스트 내에서 필요한 다른 정리를 수행합니다. 그런 다음이 래퍼를 스레드 풀에 제공하십시오. 어떤 스레드 풀 구현 (예 : before/afterExecute 메서드가없는 스레드)에서도 작동합니다.

+0

스레드 수명주기에 연결하는 것이 문제가 아닙니다. ThreadPoolExecutor를 사용하고 있으므로 afterExecute 메서드를 사용해야합니다. 문제는 스레드가 주어집니다. 어떻게 스레드 로컬 저장소를 열거합니까? 나는 그것이 비어 있는지 확인하고 싶지 않다면 경고를 남기고 싶다. –

+0

스레드 로컬 사용을 제어 할 수 있습니까? 개발자가 직접 구현을 사용하도록 할 수 있습니까? 목표 달성을 돕기 위해 ThreadLocal을 확장 할 수 있습니다. – Armadillo

0

소스에서 보면 매우 빡빡합니다. 모든 것은 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

:

는 여기에 기존 클래스에 로깅을 추가 발견되는 예입니다. 나중에 메서드를 호출 할 수 있도록 리플렉션을 사용하여 메서드에 대한 핸들을 가져와야합니다.

참고 : 제한된 환경 (애플릿 또는 응용 프로그램 서버)에서 실행되는 경우 보안 메커니즘이 일반적으로 시스템 클래스를 망칠 수 없으므로이 기능은 작동하지 않습니다.

2

'또 다른 좋은 방법'을 따라, 기존 스레드 로컬의 스냅 샷을 찍은 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); 
           } 
          } 
         } 
        } 
       } 
      } 
    } 
} 

+0

Btw, 내 필요는 HtmlUnit (또는 Selenium headless)을 스레드 로컬 메모리 누수로 고통받는 스레드 풀에서 사용하는 것이 었습니다. – karmakaze

+0

코드가 컴파일되지 않습니다. – mrswadge

+0

코드에 대한 HTML 위생 처리가 다소 엉망이 된 것 같습니다. 제네릭 형식 및 꺾쇠 괄호 주위에 문자가 없습니다. 그것의 대부분은 짐작할 수 있습니다. 이 소스를 다시 찾고 업데이트 할 수 있는지 확인합니다. – karmakaze