Re: ThreadLocalRandom initial seed
Martin Buchholz <martinrb <at> google.com>
2011-06-03 21:35:52 GMT
This is my fault.
As penance, here's a test for the TLR tck testcase:
Index: ThreadLocalRandomTest.java
===================================================================
RCS file: /export/home/jsr166/jsr166/jsr166/src/test/tck/ThreadLocalRandomTest.java,v
retrieving revision 1.10
diff -u -r1.10 ThreadLocalRandomTest.java
--- ThreadLocalRandomTest.java 31 May 2011 16:16:24 -0000 1.10
+++ ThreadLocalRandomTest.java 3 Jun 2011 21:29:51 -0000
<at> <at> -6,6 +6,8 <at> <at>
import junit.framework.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
public class ThreadLocalRandomTest extends JSR166TestCase {
<at> <at> -252,4 +254,40 <at> <at>
}
}
+ /**
+ * Different threads produce different pseudo-random sequences
+ */
+ public void testDifferentSequences() {
+ // Don't use main thread's ThreadLocalRandom - it is likely to
+ // be polluted by previous tests.
+ final AtomicReference<ThreadLocalRandom> threadLocalRandom =
+ new AtomicReference<ThreadLocalRandom>();
+ final AtomicLong rand = new AtomicLong();
+
+ long firstRand = 0;
+ ThreadLocalRandom firstThreadLocalRandom = null;
+
+ final CheckedRunnable getRandomState = new CheckedRunnable() {
+ public void realRun() {
+ ThreadLocalRandom current = ThreadLocalRandom.current();
+ assertSame(current, ThreadLocalRandom.current());
+ assertNotSame(current, threadLocalRandom.get());
+ rand.set(current.nextLong());
+ threadLocalRandom.set(current);
+ }};
+
+ Thread first = newStartedThread(getRandomState);
+ awaitTermination(first);
+ firstRand = rand.get();
+ firstThreadLocalRandom = threadLocalRandom.get();
+
+ for (int i = 0; i < NCALLS; i++) {
+ Thread t = newStartedThread(getRandomState);
+ awaitTermination(t);
+ if (firstRand != rand.get())
+ return;
+ }
+ fail("all threads generate the same pseudo-random sequence");
+ }
+
}
and here's a fix for Random.java:
I tried to save a couple of volatile writes in the common case, and
this is a slightly gross way of continuing to do that:
(of course, the "clean" version of this works as well)
diff --git a/src/share/classes/java/util/Random.java
b/src/share/classes/java/util/Random.java
--- a/src/share/classes/java/util/Random.java
+++ b/src/share/classes/java/util/Random.java
<at> <at> -118,7 +118,13 <at> <at>
* <at> see #setSeed(long)
*/
public Random(long seed) {
- this.seed = new AtomicLong(initialScramble(seed));
+ if (getClass() == Random.class)
+ this.seed = new AtomicLong(initialScramble(seed));
+ else {
+ // subclass might have overriden setSeed
+ this.seed = new AtomicLong(0L);
+ setSeed(seed);
+ }
}
private static long initialScramble(long seed) {