Ensure ObjectCleaner will also be used when FastThreadLocal.set is used.

Motivation:

e329ca1 introduced the user of ObjectCleaner in FastThreadLocal but we missed the case to register our cleaner task if FastThreadLocal.set was called only.

Modifications:

- Use ObjectCleaner also when FastThreadLocal.set is used.
- Add test case.

Result:

ObjectCleaner is always used.
This commit is contained in:
Norman Maurer 2017-12-21 20:35:32 +01:00
parent 6b033c51a5
commit e004b4a354
2 changed files with 35 additions and 10 deletions

View File

@ -134,13 +134,18 @@ public class FastThreadLocal<V> {
*/
@SuppressWarnings("unchecked")
public final V get() {
final InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
V value = initialize(threadLocalMap);
registerCleaner(threadLocalMap);
return value;
}
private void registerCleaner(final InternalThreadLocalMap threadLocalMap) {
Thread current = Thread.currentThread();
if (!FastThreadLocalThread.willCleanupFastThreadLocals(current)) {
// We will need to ensure we will trigger remove(InternalThreadLocalMap) so everything will be released
@ -155,7 +160,6 @@ public class FastThreadLocal<V> {
}
});
}
return value;
}
/**
@ -190,7 +194,13 @@ public class FastThreadLocal<V> {
*/
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
set(InternalThreadLocalMap.get(), value);
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
boolean alreadySet = threadLocalMap.isIndexedVariableSet(index);
set(threadLocalMap, value);
if (!alreadySet) {
registerCleaner(threadLocalMap);
}
} else {
remove();
}

View File

@ -77,16 +77,26 @@ public class FastThreadLocalTest {
}
@Test(timeout = 4000)
public void testOnRemoveCalledForFastThreadLocal() throws Exception {
testOnRemoveCalled(true);
public void testOnRemoveCalledForFastThreadLocalGet() throws Exception {
testOnRemoveCalled(true, true);
}
@Test(timeout = 4000)
public void testOnRemoveCalledForNonFastThreadLocal() throws Exception {
testOnRemoveCalled(false);
public void testOnRemoveCalledForNonFastThreadLocalGet() throws Exception {
testOnRemoveCalled(false, true);
}
private static void testOnRemoveCalled(boolean fastThreadLocal) throws Exception {
@Test(timeout = 4000)
public void testOnRemoveCalledForFastThreadLocalSet() throws Exception {
testOnRemoveCalled(true, false);
}
@Test(timeout = 4000)
public void testOnRemoveCalledForNonFastThreadLocalSet() throws Exception {
testOnRemoveCalled(false, false);
}
private static void testOnRemoveCalled(boolean fastThreadLocal, final boolean callGet) throws Exception {
final TestFastThreadLocal threadLocal = new TestFastThreadLocal();
final TestFastThreadLocal threadLocal2 = new TestFastThreadLocal();
@ -94,8 +104,13 @@ public class FastThreadLocalTest {
Runnable runnable = new Runnable() {
@Override
public void run() {
assertEquals(Thread.currentThread().getName(), threadLocal.get());
assertEquals(Thread.currentThread().getName(), threadLocal2.get());
if (callGet) {
assertEquals(Thread.currentThread().getName(), threadLocal.get());
assertEquals(Thread.currentThread().getName(), threadLocal2.get());
} else {
threadLocal.set(Thread.currentThread().getName());
threadLocal2.set(Thread.currentThread().getName());
}
}
};
Thread thread = fastThreadLocal ? new FastThreadLocalThread(runnable) : new Thread(runnable);