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 java.util.concurrent.ThreadLocalRandom;
10 import java.util.concurrent.atomic.AtomicLong;
11 import java.util.concurrent.atomic.AtomicReference;
12 
13 import junit.framework.Test;
14 import junit.framework.TestSuite;
15 
16 public class ThreadLocalRandomTest extends JSR166TestCase {
17 
18     // android-note: Removed because the CTS runner does a bad job of
19     // retrying tests that have suite() declarations.
20     //
21     // public static void main(String[] args) {
22     //     main(suite(), args);
23     // }
24     // public static Test suite() {
25     //     return new TestSuite(ThreadLocalRandomTest.class);
26     // }
27 
28     /*
29      * Testing coverage notes:
30      *
31      * We don't test randomness properties, but only that repeated
32      * calls, up to NCALLS tries, produce at least one different
33      * result.  For bounded versions, we sample various intervals
34      * across multiples of primes.
35      */
36 
37     // max numbers of calls to detect getting stuck on one value
38     static final int NCALLS = 10000;
39 
40     // max sampled int bound
41     static final int MAX_INT_BOUND = (1 << 28);
42 
43     // max sampled long bound
44     static final long MAX_LONG_BOUND = (1L << 42);
45 
46     // Number of replications for other checks
47     static final int REPS = 20;
48 
49     /**
50      * setSeed throws UnsupportedOperationException
51      */
testSetSeed()52     public void testSetSeed() {
53         try {
54             ThreadLocalRandom.current().setSeed(17);
55             shouldThrow();
56         } catch (UnsupportedOperationException success) {}
57     }
58 
59     /**
60      * Repeated calls to nextInt produce at least two distinct results
61      */
testNextInt()62     public void testNextInt() {
63         int f = ThreadLocalRandom.current().nextInt();
64         int i = 0;
65         while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
66             ++i;
67         assertTrue(i < NCALLS);
68     }
69 
70     /**
71      * Repeated calls to nextLong produce at least two distinct results
72      */
73     public void testNextLong() {
74         long f = ThreadLocalRandom.current().nextLong();
75         int i = 0;
76         while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
77             ++i;
78         assertTrue(i < NCALLS);
79     }
80 
81     /**
82      * Repeated calls to nextBoolean produce at least two distinct results
83      */
84     public void testNextBoolean() {
85         boolean f = ThreadLocalRandom.current().nextBoolean();
86         int i = 0;
87         while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
88             ++i;
89         assertTrue(i < NCALLS);
90     }
91 
92     /**
93      * Repeated calls to nextFloat produce at least two distinct results
94      */
95     public void testNextFloat() {
96         float f = ThreadLocalRandom.current().nextFloat();
97         int i = 0;
98         while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
99             ++i;
100         assertTrue(i < NCALLS);
101     }
102 
103     /**
104      * Repeated calls to nextDouble produce at least two distinct results
105      */
106     public void testNextDouble() {
107         double f = ThreadLocalRandom.current().nextDouble();
108         int i = 0;
109         while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
110             ++i;
111         assertTrue(i < NCALLS);
112     }
113 
114     /**
115      * Repeated calls to nextGaussian produce at least two distinct results
116      */
117     public void testNextGaussian() {
118         double f = ThreadLocalRandom.current().nextGaussian();
119         int i = 0;
120         while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
121             ++i;
122         assertTrue(i < NCALLS);
123     }
124 
125     /**
126      * nextInt(non-positive) throws IllegalArgumentException
127      */
128     public void testNextIntBoundNonPositive() {
129         ThreadLocalRandom rnd = ThreadLocalRandom.current();
130         for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
131             try {
132                 rnd.nextInt(bound);
133                 shouldThrow();
134             } catch (IllegalArgumentException success) {}
135         }
136     }
137 
138     /**
139      * nextInt(least >= bound) throws IllegalArgumentException
140      */
141     public void testNextIntBadBounds() {
142         int[][] badBoundss = {
143             { 17, 2 },
144             { -42, -42 },
145             { Integer.MAX_VALUE, Integer.MIN_VALUE },
146         };
147         ThreadLocalRandom rnd = ThreadLocalRandom.current();
148         for (int[] badBounds : badBoundss) {
149             try {
150                 rnd.nextInt(badBounds[0], badBounds[1]);
151                 shouldThrow();
152             } catch (IllegalArgumentException success) {}
153         }
154     }
155 
156     /**
157      * nextInt(bound) returns 0 <= value < bound;
158      * repeated calls produce at least two distinct results
159      */
160     public void testNextIntBounded() {
161         // sample bound space across prime number increments
162         for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
163             int f = ThreadLocalRandom.current().nextInt(bound);
164             assertTrue(0 <= f && f < bound);
165             int i = 0;
166             int j;
167             while (i < NCALLS &&
168                    (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
169                 assertTrue(0 <= j && j < bound);
170                 ++i;
171             }
172             assertTrue(i < NCALLS);
173         }
174     }
175 
176     /**
177      * nextInt(least, bound) returns least <= value < bound;
178      * repeated calls produce at least two distinct results
179      */
180     public void testNextIntBounded2() {
181         for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
182             for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
183                 int f = ThreadLocalRandom.current().nextInt(least, bound);
184                 assertTrue(least <= f && f < bound);
185                 int i = 0;
186                 int j;
187                 while (i < NCALLS &&
188                        (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
189                     assertTrue(least <= j && j < bound);
190                     ++i;
191                 }
192                 assertTrue(i < NCALLS);
193             }
194         }
195     }
196 
197     /**
198      * nextLong(non-positive) throws IllegalArgumentException
199      */
200     public void testNextLongBoundNonPositive() {
201         ThreadLocalRandom rnd = ThreadLocalRandom.current();
202         for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
203             try {
204                 rnd.nextLong(bound);
205                 shouldThrow();
206             } catch (IllegalArgumentException success) {}
207         }
208     }
209 
210     /**
211      * nextLong(least >= bound) throws IllegalArgumentException
212      */
213     public void testNextLongBadBounds() {
214         long[][] badBoundss = {
215             { 17L, 2L },
216             { -42L, -42L },
217             { Long.MAX_VALUE, Long.MIN_VALUE },
218         };
219         ThreadLocalRandom rnd = ThreadLocalRandom.current();
220         for (long[] badBounds : badBoundss) {
221             try {
222                 rnd.nextLong(badBounds[0], badBounds[1]);
223                 shouldThrow();
224             } catch (IllegalArgumentException success) {}
225         }
226     }
227 
228     /**
229      * nextLong(bound) returns 0 <= value < bound;
230      * repeated calls produce at least two distinct results
231      */
232     public void testNextLongBounded() {
233         for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
234             long f = ThreadLocalRandom.current().nextLong(bound);
235             assertTrue(0 <= f && f < bound);
236             int i = 0;
237             long j;
238             while (i < NCALLS &&
239                    (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
240                 assertTrue(0 <= j && j < bound);
241                 ++i;
242             }
243             assertTrue(i < NCALLS);
244         }
245     }
246 
247     /**
248      * nextLong(least, bound) returns least <= value < bound;
249      * repeated calls produce at least two distinct results
250      */
251     public void testNextLongBounded2() {
252         for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
253             for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
254                 long f = ThreadLocalRandom.current().nextLong(least, bound);
255                 assertTrue(least <= f && f < bound);
256                 int i = 0;
257                 long j;
258                 while (i < NCALLS &&
259                        (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
260                     assertTrue(least <= j && j < bound);
261                     ++i;
262                 }
263                 assertTrue(i < NCALLS);
264             }
265         }
266     }
267 
268     /**
269      * nextDouble(non-positive) throws IllegalArgumentException
270      */
271     public void testNextDoubleBoundNonPositive() {
272         ThreadLocalRandom rnd = ThreadLocalRandom.current();
273         double[] badBounds = {
274             0.0d,
275             -17.0d,
276             -Double.MIN_VALUE,
277             Double.NEGATIVE_INFINITY,
278             Double.NaN,
279         };
280         for (double bound : badBounds) {
281             try {
282                 rnd.nextDouble(bound);
283                 shouldThrow();
284             } catch (IllegalArgumentException success) {}
285         }
286     }
287 
288     /**
289      * nextDouble(least, bound) returns least <= value < bound;
290      * repeated calls produce at least two distinct results
291      */
292     public void testNextDoubleBounded2() {
293         for (double least = 0.0001; least < 1.0e20; least *= 8) {
294             for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
295                 double f = ThreadLocalRandom.current().nextDouble(least, bound);
296                 assertTrue(least <= f && f < bound);
297                 int i = 0;
298                 double j;
299                 while (i < NCALLS &&
300                        (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
301                     assertTrue(least <= j && j < bound);
302                     ++i;
303                 }
304                 assertTrue(i < NCALLS);
305             }
306         }
307     }
308 
309     /**
310      * Different threads produce different pseudo-random sequences
311      */
312     public void testDifferentSequences() {
313         // Don't use main thread's ThreadLocalRandom - it is likely to
314         // be polluted by previous tests.
315         final AtomicReference<ThreadLocalRandom> threadLocalRandom =
316             new AtomicReference<ThreadLocalRandom>();
317         final AtomicLong rand = new AtomicLong();
318 
319         long firstRand = 0;
320         ThreadLocalRandom firstThreadLocalRandom = null;
321 
322         Runnable getRandomState = new CheckedRunnable() {
323             public void realRun() {
324                 ThreadLocalRandom current = ThreadLocalRandom.current();
325                 assertSame(current, ThreadLocalRandom.current());
326                 // test bug: the following is not guaranteed and not true in JDK8
327                 //                assertNotSame(current, threadLocalRandom.get());
328                 rand.set(current.nextLong());
329                 threadLocalRandom.set(current);
330             }};
331 
332         Thread first = newStartedThread(getRandomState);
333         awaitTermination(first);
334         firstRand = rand.get();
335         firstThreadLocalRandom = threadLocalRandom.get();
336 
337         for (int i = 0; i < NCALLS; i++) {
338             Thread t = newStartedThread(getRandomState);
339             awaitTermination(t);
340             if (firstRand != rand.get())
341                 return;
342         }
343         fail("all threads generate the same pseudo-random sequence");
344     }
345 
346 }
347