1 /*
2  * Written by Doug Lea with assistance from members of JCP JSR-166
3  * Expert Group and released to the public domain, as explained at
4  * http://creativecommons.org/publicdomain/zero/1.0/
5  */
6 
7 package jsr166;
8 
9 import junit.framework.*;
10 import java.util.*;
11 import java.util.concurrent.ThreadLocalRandom;
12 import java.util.concurrent.atomic.AtomicLong;
13 import java.util.concurrent.atomic.AtomicReference;
14 
15 public class ThreadLocalRandomTest extends JSR166TestCase {
16 
17     /*
18      * Testing coverage notes:
19      *
20      * We don't test randomness properties, but only that repeated
21      * calls, up to NCALLS tries, produce at least one different
22      * result.  For bounded versions, we sample various intervals
23      * across multiples of primes.
24      */
25 
26     //
27     static final int NCALLS = 10000;
28 
29     // max sampled int bound
30     static final int MAX_INT_BOUND = (1 << 28);
31 
32     // Max sampled long bound
33     static final long MAX_LONG_BOUND = (1L << 42);
34 
35     /**
36      * setSeed throws UnsupportedOperationException
37      */
testSetSeed()38     public void testSetSeed() {
39         try {
40             ThreadLocalRandom.current().setSeed(17);
41             shouldThrow();
42         } catch (UnsupportedOperationException success) {}
43     }
44 
45     /**
46      * Repeated calls to nextInt produce at least one different result
47      */
testNextInt()48     public void testNextInt() {
49         int f = ThreadLocalRandom.current().nextInt();
50         int i = 0;
51         while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
52             ++i;
53         assertTrue(i < NCALLS);
54     }
55 
56     /**
57      * Repeated calls to nextLong produce at least one different result
58      */
59     public void testNextLong() {
60         long f = ThreadLocalRandom.current().nextLong();
61         int i = 0;
62         while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
63             ++i;
64         assertTrue(i < NCALLS);
65     }
66 
67     /**
68      * Repeated calls to nextBoolean produce at least one different result
69      */
70     public void testNextBoolean() {
71         boolean f = ThreadLocalRandom.current().nextBoolean();
72         int i = 0;
73         while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
74             ++i;
75         assertTrue(i < NCALLS);
76     }
77 
78     /**
79      * Repeated calls to nextFloat produce at least one different result
80      */
81     public void testNextFloat() {
82         float f = ThreadLocalRandom.current().nextFloat();
83         int i = 0;
84         while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
85             ++i;
86         assertTrue(i < NCALLS);
87     }
88 
89     /**
90      * Repeated calls to nextDouble produce at least one different result
91      */
92     public void testNextDouble() {
93         double f = ThreadLocalRandom.current().nextDouble();
94         double i = 0;
95         while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
96             ++i;
97         assertTrue(i < NCALLS);
98     }
99 
100     /**
101      * Repeated calls to nextGaussian produce at least one different result
102      */
103     public void testNextGaussian() {
104         double f = ThreadLocalRandom.current().nextGaussian();
105         int i = 0;
106         while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
107             ++i;
108         assertTrue(i < NCALLS);
109     }
110 
111     /**
112      * nextInt(negative) throws IllegalArgumentException;
113      */
114     public void testNextIntBoundedNeg() {
115         try {
116             int f = ThreadLocalRandom.current().nextInt(-17);
117             shouldThrow();
118         } catch (IllegalArgumentException success) {}
119     }
120 
121     /**
122      * nextInt(least >= bound) throws IllegalArgumentException;
123      */
124     public void testNextIntBadBounds() {
125         try {
126             int f = ThreadLocalRandom.current().nextInt(17, 2);
127             shouldThrow();
128         } catch (IllegalArgumentException success) {}
129     }
130 
131     /**
132      * nextInt(bound) returns 0 <= value < bound;
133      * repeated calls produce at least one different result
134      */
135     public void testNextIntBounded() {
136         // sample bound space across prime number increments
137         for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
138             int f = ThreadLocalRandom.current().nextInt(bound);
139             assertTrue(0 <= f && f < bound);
140             int i = 0;
141             int j;
142             while (i < NCALLS &&
143                    (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
144                 assertTrue(0 <= j && j < bound);
145                 ++i;
146             }
147             assertTrue(i < NCALLS);
148         }
149     }
150 
151     /**
152      * nextInt(least, bound) returns least <= value < bound;
153      * repeated calls produce at least one different result
154      */
155     public void testNextIntBounded2() {
156         for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
157             for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
158                 int f = ThreadLocalRandom.current().nextInt(least, bound);
159                 assertTrue(least <= f && f < bound);
160                 int i = 0;
161                 int j;
162                 while (i < NCALLS &&
163                        (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
164                     assertTrue(least <= j && j < bound);
165                     ++i;
166                 }
167                 assertTrue(i < NCALLS);
168             }
169         }
170     }
171 
172     /**
173      * nextLong(negative) throws IllegalArgumentException;
174      */
175     public void testNextLongBoundedNeg() {
176         try {
177             long f = ThreadLocalRandom.current().nextLong(-17);
178             shouldThrow();
179         } catch (IllegalArgumentException success) {}
180     }
181 
182     /**
183      * nextLong(least >= bound) throws IllegalArgumentException;
184      */
185     public void testNextLongBadBounds() {
186         try {
187             long f = ThreadLocalRandom.current().nextLong(17, 2);
188             shouldThrow();
189         } catch (IllegalArgumentException success) {}
190     }
191 
192     /**
193      * nextLong(bound) returns 0 <= value < bound;
194      * repeated calls produce at least one different result
195      */
196     public void testNextLongBounded() {
197         for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
198             long f = ThreadLocalRandom.current().nextLong(bound);
199             assertTrue(0 <= f && f < bound);
200             int i = 0;
201             long j;
202             while (i < NCALLS &&
203                    (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
204                 assertTrue(0 <= j && j < bound);
205                 ++i;
206             }
207             assertTrue(i < NCALLS);
208         }
209     }
210 
211     /**
212      * nextLong(least, bound) returns least <= value < bound;
213      * repeated calls produce at least one different result
214      */
215     public void testNextLongBounded2() {
216         for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
217             for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
218                 long f = ThreadLocalRandom.current().nextLong(least, bound);
219                 assertTrue(least <= f && f < bound);
220                 int i = 0;
221                 long j;
222                 while (i < NCALLS &&
223                        (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
224                     assertTrue(least <= j && j < bound);
225                     ++i;
226                 }
227                 assertTrue(i < NCALLS);
228             }
229         }
230     }
231 
232     /**
233      * nextDouble(least, bound) returns least <= value < bound;
234      * repeated calls produce at least one different result
235      */
236     public void testNextDoubleBounded2() {
237         for (double least = 0.0001; least < 1.0e20; least *= 8) {
238             for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
239                 double f = ThreadLocalRandom.current().nextDouble(least, bound);
240                 assertTrue(least <= f && f < bound);
241                 int i = 0;
242                 double j;
243                 while (i < NCALLS &&
244                        (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
245                     assertTrue(least <= j && j < bound);
246                     ++i;
247                 }
248                 assertTrue(i < NCALLS);
249             }
250         }
251     }
252 
253     /**
254      * Different threads produce different pseudo-random sequences
255      */
256     public void testDifferentSequences() {
257         // Don't use main thread's ThreadLocalRandom - it is likely to
258         // be polluted by previous tests.
259         final AtomicReference<ThreadLocalRandom> threadLocalRandom =
260             new AtomicReference<ThreadLocalRandom>();
261         final AtomicLong rand = new AtomicLong();
262 
263         long firstRand = 0;
264         ThreadLocalRandom firstThreadLocalRandom = null;
265 
266         final CheckedRunnable getRandomState = new CheckedRunnable() {
267             public void realRun() {
268                 ThreadLocalRandom current = ThreadLocalRandom.current();
269                 assertSame(current, ThreadLocalRandom.current());
270                 // test bug: the following is not guaranteed and not true in JDK8
271                 //                assertNotSame(current, threadLocalRandom.get());
272                 rand.set(current.nextLong());
273                 threadLocalRandom.set(current);
274             }};
275 
276         Thread first = newStartedThread(getRandomState);
277         awaitTermination(first);
278         firstRand = rand.get();
279         firstThreadLocalRandom = threadLocalRandom.get();
280 
281         for (int i = 0; i < NCALLS; i++) {
282             Thread t = newStartedThread(getRandomState);
283             awaitTermination(t);
284             if (firstRand != rand.get())
285                 return;
286         }
287         fail("all threads generate the same pseudo-random sequence");
288     }
289 
290 }
291