【问题标题】:Thread's ThreadLocals cleaning线程的 ThreadLocals 清理
【发布时间】:2019-05-11 10:45:21
【问题描述】:

here我找到了以下代码如何在Java中清理线程的ThreadLocals:

private void cleanThreadLocals() {
    try {
        // Get a reference to the thread locals table of the current thread
        Thread thread = Thread.currentThread();
        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        Object threadLocalTable = threadLocalsField.get(thread);

        // Get a reference to the array holding the thread local variables inside the
        // ThreadLocalMap of the current thread
        Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
        Field tableField = threadLocalMapClass.getDeclaredField("table");
        tableField.setAccessible(true);
        Object table = tableField.get(threadLocalTable);

        // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
        // is a reference to the actual ThreadLocal variable
        Field referentField = Reference.class.getDeclaredField("referent");
        referentField.setAccessible(true);

        for (int i=0; i < Array.getLength(table); i++) {
            // Each entry in the table array of ThreadLocalMap is an Entry object
            // representing the thread local reference and its value
            Object entry = Array.get(table, i);
            if (entry != null) {
                // Get a reference to the thread local object and remove it from the table
                ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
                threadLocal.remove();
            }
        }
    } catch(Exception e) {
        // We will tolerate an exception here and just log it
        throw new IllegalStateException(e);
    }
}

这很复杂。遵循更简单的代码怎么样,清理 ThreadLocals 就足够了吗?谢谢。

private void cleanThreadLocals(Thread thread) {
    try {
        // Get a reference to the thread locals table of the current thread
        Thread thread = Thread.currentThread();
        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        threadLocalsField.set(thread, null);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

【问题讨论】:

    标签: java multithreading reflection concurrency thread-local


    【解决方案1】:

    两个 sn-ps clean ThreadLocals,但他们有不同的方法。

    较长的 sn-p 首先从 ThreadLocalMap 中获取所有线程 ThreadLocals 并对其调用 remove() 方法。您只能将它用于当前线程,因为 remove() 方法只是从当前线程中删除()值,没有办法指定它应该使用哪个线程。通过一些修改,您可以将其用于任何线程,您必须直接在 ThreadLocalMap 上调用 remove()。

    较短的 sn-p 从 Thread 中删除整个 ThreadLocalMap 实例。它是延迟初始化的,因此如果需要,它将再次创建。您可以将此方法用于任何线程。

    我测试了是否所有实例都从 JVM 中删除。该测试依赖于 GC 行为,您可能需要在某些环境中调整 GC 行为,但在我的环境 win10/OracleJava8 上它开箱即用。

    测试:

    @Test
    public void howToCleanThreadLocalValues() throws ReflectiveOperationException {
        Thread thread = Thread.currentThread();
    
        // Set thread local value for current thread
        WeakReference<ThreadLocal> threadLocal = new WeakReference<>(new ThreadLocal<>());
        threadLocal.get().set("foo");
    
        // Get ThreadLocalMap
        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        WeakReference<Object> threadLocalMap = new WeakReference<>(threadLocalsField.get(thread));
        Assert.assertNotNull(threadLocalMap.get());
        Assert.assertNotNull(threadLocal.get());
    
        // Set ThreadLocalMap to null, GC do the rest
        threadLocalsField.set(Thread.currentThread(), null);
        System.gc();
        Assert.assertNull(threadLocalMap.get());
        Assert.assertNull(threadLocal.get());
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-21
      • 2020-01-05
      • 2011-06-30
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 1970-01-01
      相关资源
      最近更新 更多