Duplicate :
|
FULL PRODUCT VERSION : A DESCRIPTION OF THE PROBLEM : The example in http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html is: import java.util.concurrent.atomic.AtomicInteger; public class UniqueThreadIdGenerator { private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal < Integer > uniqueNum = new ThreadLocal < Integer > () { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; public static int getCurrentThreadId() { return uniqueId.get(); } } // UniqueThreadIdGenerator while it should be: import java.util.concurrent.atomic.AtomicInteger; public class UniqueThreadIdGenerator { private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal < Integer > uniqueNum = new ThreadLocal < Integer > () { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; public static int getCurrentThreadId() { return uniqueNum.get(); } } // UniqueThreadIdGenerator STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Run getCurrentThreadId() with many threads EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - getCurrentThreadID() should return a new id for each thread. ACTUAL - getCurrentThreadID() always returns 0. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; public class UniqueThreadIdGeneratorTest { // Broken UniqueThreadIdGenerator from // http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html public static class UniqueThreadIdGenerator { private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal<Integer> uniqueNum = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; public static int getCurrentThreadId() { return uniqueId.get(); } } // UniqueThreadIdGenerator @Test public void testThreadLocalUsage() throws Exception { final int numberOfThreads = 10; CountDownLatch counter = new CountDownLatch(numberOfThreads); ConcurrentSkipListSet<Integer> threadIds = new ConcurrentSkipListSet<Integer>(); for (int i = 0; i < numberOfThreads; i++) { new Thread(createRunnable(threadIds, counter)).start(); } counter.await(); List<Integer> expectedThreadIds = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); assertEquals(expectedThreadIds, new ArrayList<Integer>(threadIds)); } private Runnable createRunnable(final ConcurrentSkipListSet<Integer> threadIds, final CountDownLatch counter) { return new Runnable() { @Override public void run() { threadIds.add(UniqueThreadIdGenerator.getCurrentThreadId()); counter.countDown(); } }; } } ---------- END SOURCE ----------