Оба фрагмента очищают ThreadLocals, но имеют другой подход.
Более длинный фрагмент сначала получает все ThreadLocals из ThreadLocalMap и вызывает метод remove () для них.Вы можете использовать его только для текущего потока, потому что метод remove () просто удаляет значение () из текущего потока, и нет способа указать, с каким потоком он должен работать.С некоторыми изменениями вы можете использовать его для любого потока, вам придется напрямую вызывать remove () в ThreadLocalMap.
Более короткий фрагмент удаляет весь экземпляр ThreadLocalMap из Thread.Он лениво инициализируется, поэтому при необходимости он будет создан заново.Вы можете использовать этот подход для любого потока.
Я проверил, все ли экземпляры удалены из JVM.Тест основан на поведении GC, вам, возможно, понадобится настроить поведение GC в какой-либо среде, но в моей среде win10 / OracleJava8 он проходит "из коробки".
Test:
@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());
}