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 ----------
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 ----------
- duplicates
-
JDK-6434084 (doc thread) New ThreadLocal SerialNum example still has problems
-
- Resolved
-