[concurrency-interest] ThreadLocalRandom initial seed

Martin Buchholz martinrb at google.com
Fri Jun 3 17:35:52 EDT 2011


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
@@ -6,6 +6,8 @@
 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 {

@@ -252,4 +254,40 @@
         }
     }

+    /**
+     * 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
@@ -118,7 +118,13 @@
      * @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) {


More information about the Concurrency-interest mailing list