diff --git a/src/main/java/org/apache/sling/commons/threads/impl/ThreadLocalCleaner.java b/src/main/java/org/apache/sling/commons/threads/impl/ThreadLocalCleaner.java index 6a0a067..98f264f 100644 --- a/src/main/java/org/apache/sling/commons/threads/impl/ThreadLocalCleaner.java +++ b/src/main/java/org/apache/sling/commons/threads/impl/ThreadLocalCleaner.java @@ -41,8 +41,13 @@ public class ThreadLocalCleaner { /** this field is in class {@code ThreadLocal.ThreadLocalMap.Entry} and contains an object referencing the actual thread local * variable */ private static Field threadLocalEntryValueField; + /** this field is in the class {@code ThreadLocal.ThreadLocalMap} and contains the number of the entries */ + private static Field threadLocalMapSizeField; + /** this field is in the class {@code ThreadLocal.ThreadLocalMap} and next resize threshold */ + private static Field threadLocalMapThresholdField; private static IllegalStateException reflectionException; + public ThreadLocalCleaner(ThreadLocalChangeListener listener) { if (threadLocalsField == null) { initReflectionFields(); @@ -65,6 +70,8 @@ private static synchronized void initReflectionFields() throws IllegalStateExcep tableField = field(threadLocalMapClass, "table"); threadLocalMapEntryClass = inner(threadLocalMapClass, "Entry"); threadLocalEntryValueField = field(threadLocalMapEntryClass, "value"); + threadLocalMapSizeField = field(threadLocalMapClass, "size"); + threadLocalMapThresholdField = field(threadLocalMapClass, "threshold"); } catch (NoSuchFieldException e) { reflectionException = new IllegalStateException( "Could not locate threadLocals field in class Thread. " + @@ -169,12 +176,19 @@ private static Class inner(Class clazz, String name) { } private static final ThreadLocal[]> copyOfThreadLocals = new ThreadLocal<>(); - + private static final ThreadLocal copyOfThreadLocalsSize = new ThreadLocal<>(); + private static final ThreadLocal copyOfThreadLocalsThreshold = new ThreadLocal<>(); private static final ThreadLocal[]> copyOfInheritableThreadLocals = new ThreadLocal<>(); + private static final ThreadLocal copyOfInheritableThreadLocalsSize = new ThreadLocal<>(); + private static final ThreadLocal copyOfInheritableThreadLocalsThreshold = new ThreadLocal<>(); private static void saveOldThreadLocals() { copyOfThreadLocals.set(copy(threadLocalsField)); + copyOfThreadLocalsSize.set(size(threadLocalsField, threadLocalMapSizeField)); + copyOfThreadLocalsThreshold.set(size(threadLocalsField, threadLocalMapThresholdField)); copyOfInheritableThreadLocals.set(copy(inheritableThreadLocalsField)); + copyOfInheritableThreadLocalsSize.set(size(inheritableThreadLocalsField, threadLocalMapSizeField)); + copyOfInheritableThreadLocalsThreshold.set(size(inheritableThreadLocalsField, threadLocalMapThresholdField)); } private static Reference[] copy(Field field) { @@ -190,31 +204,43 @@ private static Reference[] copy(Field field) { } } + private static Integer size(Field field, Field sizeField) { + try { + Thread thread = Thread.currentThread(); + Object threadLocals = field.get(thread); + if (threadLocals == null) + return null; + return (Integer) sizeField.get(threadLocals); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Access denied", e); + } + } + private static void restoreOldThreadLocals() { try { - restore(inheritableThreadLocalsField, copyOfInheritableThreadLocals.get()); - restore(threadLocalsField, copyOfThreadLocals.get()); + restore(inheritableThreadLocalsField, copyOfInheritableThreadLocals.get(), + copyOfInheritableThreadLocalsSize.get(), copyOfInheritableThreadLocalsThreshold.get()); + restore(threadLocalsField, copyOfThreadLocals.get(), + copyOfThreadLocalsSize.get(), copyOfThreadLocalsThreshold.get()); } finally { copyOfThreadLocals.remove(); copyOfInheritableThreadLocals.remove(); } } - private static void restore(Field field, Object value) { + private static void restore(Field field, Object value, Integer size, Integer threshold) { try { Thread thread = Thread.currentThread(); if (value == null) { field.set(thread, null); } else { - tableField.set(field.get(thread), value); + final Object threadLocals = field.get(thread); + tableField.set(threadLocals, value); + threadLocalMapSizeField.set(threadLocals, size); + threadLocalMapThresholdField.set(threadLocals, threshold); } } catch (IllegalAccessException e) { throw new IllegalStateException("Access denied", e); } } - - static { - // TODO: move to a place where the exception can be caught! - - } } \ No newline at end of file diff --git a/src/test/java/org/apache/sling/commons/threads/impl/ThreadPoolExecutorCleaningThreadLocalsTest.java b/src/test/java/org/apache/sling/commons/threads/impl/ThreadPoolExecutorCleaningThreadLocalsTest.java index 7e6b92a..0160e64 100644 --- a/src/test/java/org/apache/sling/commons/threads/impl/ThreadPoolExecutorCleaningThreadLocalsTest.java +++ b/src/test/java/org/apache/sling/commons/threads/impl/ThreadPoolExecutorCleaningThreadLocalsTest.java @@ -57,7 +57,6 @@ public void setUp() { } @Test(timeout = 10000) - @Ignore public void threadLocalCleanupWorksWithResize() throws Exception { // configure thread local counts to make sure that