How to clean up ThreadLocals

前端 未结 7 1658
遇见更好的自我
遇见更好的自我 2020-11-28 23:01

Does any one have an example how to do this? Are they handled by the garbage collector? I\'m using Tomcat 6.

相关标签:
7条回答
  • 2020-11-28 23:52

    @lyaffe's answer is the best possible for Java 6. There are a few issues that this answer resolves using what is available in Java 8.

    @lyaffe's answer was written for Java 6 before MethodHandle became available. It suffers from performance penalties due to reflection. If used as below, MethodHandle provides zero overhead access to fields and methods.

    @lyaffe's answer also goes through the ThreadLocalMap.table explicitly and is prone to bugs. There is a method ThreadLocalMap.expungeStaleEntries() now available that does the same thing.

    The code below has 3 initialization methods to minimize the cost of invoking expungeStaleEntries().

    private static final MethodHandle        s_getThreadLocals     = initThreadLocals();
    private static final MethodHandle        s_expungeStaleEntries = initExpungeStaleEntries();
    private static final ThreadLocal<Object> s_threadLocals        = ThreadLocal.withInitial(() -> getThreadLocals());
    
    public static void expungeThreadLocalMap()
    {
       Object threadLocals;
    
       threadLocals = s_threadLocals.get();
    
       try
       {
          s_expungeStaleEntries.invoke(threadLocals);
       }
       catch (Throwable e)
       {
          throw new IllegalStateException(e);
       }
    }
    
    private static Object getThreadLocals()
    {
       ThreadLocal<Object> local;
       Object result;
       Thread thread;
    
       local = new ThreadLocal<>();
    
       local.set(local);   // Force ThreadLocal to initialize Thread.threadLocals
    
       thread = Thread.currentThread();
    
       try
       {
          result = s_getThreadLocals.invoke(thread);
       }
       catch (Throwable e)
       {
          throw new IllegalStateException(e);
       }
    
       return(result);
    }
    
    private static MethodHandle initThreadLocals()
    {
       MethodHandle result;
       Field field;
    
       try
       {
          field = Thread.class.getDeclaredField("threadLocals");
    
          field.setAccessible(true);
    
          result = MethodHandles.
             lookup().
             unreflectGetter(field);
    
          result = Preconditions.verifyNotNull(result, "result is null");
       }
       catch (NoSuchFieldException | SecurityException | IllegalAccessException e)
       {
          throw new ExceptionInInitializerError(e);
       }
    
       return(result);
    }
    
    private static MethodHandle initExpungeStaleEntries()
    {
       MethodHandle result;
       Class<?> clazz;
       Method method;
       Object threadLocals;
    
       threadLocals = getThreadLocals();
       clazz        = threadLocals.getClass();
    
       try
       {
          method = clazz.getDeclaredMethod("expungeStaleEntries");
    
          method.setAccessible(true);
    
          result = MethodHandles.
             lookup().
             unreflect(method);
       }
       catch (NoSuchMethodException | SecurityException | IllegalAccessException e)
       {
          throw new ExceptionInInitializerError(e);
       }
    
       return(result);
    }
    
    0 讨论(0)
提交回复
热议问题