1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.
7  *
8  * This code is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * version 2 for more details (a copy is included in the LICENSE file that
12  * accompanied this code).
13  *
14  * You should have received a copy of the GNU General Public License version
15  * 2 along with this work; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19  * or visit www.oracle.com if you need additional information or have any
20  * questions.
21  */
22 
23 /*
24  * This file is available under and governed by the GNU General Public
25  * License version 2 only, as published by the Free Software Foundation.
26  * However, the following notice accompanied the original version of this
27  * file:
28  *
29  * Written by Doug Lea with assistance from members of JCP JSR-166
30  * Expert Group and released to the public domain, as explained at
31  * http://creativecommons.org/publicdomain/zero/1.0/
32  */
33 
34 import java.util.concurrent.ThreadLocalRandom;
35 import java.util.concurrent.atomic.AtomicLong;
36 import java.util.concurrent.atomic.AtomicReference;
37 
38 import junit.framework.Test;
39 import junit.framework.TestSuite;
40 
41 public class ThreadLocalRandomTest extends JSR166TestCase {
42 
main(String[] args)43     public static void main(String[] args) {
44         main(suite(), args);
45     }
suite()46     public static Test suite() {
47         return new TestSuite(ThreadLocalRandomTest.class);
48     }
49 
50     /*
51      * Testing coverage notes:
52      *
53      * We don't test randomness properties, but only that repeated
54      * calls, up to NCALLS tries, produce at least one different
55      * result.  For bounded versions, we sample various intervals
56      * across multiples of primes.
57      */
58 
59     // max numbers of calls to detect getting stuck on one value
60     static final int NCALLS = 10000;
61 
62     // max sampled int bound
63     static final int MAX_INT_BOUND = (1 << 28);
64 
65     // max sampled long bound
66     static final long MAX_LONG_BOUND = (1L << 42);
67 
68     // Number of replications for other checks
69     static final int REPS = 20;
70 
71     /**
72      * setSeed throws UnsupportedOperationException
73      */
testSetSeed()74     public void testSetSeed() {
75         try {
76             ThreadLocalRandom.current().setSeed(17);
77             shouldThrow();
78         } catch (UnsupportedOperationException success) {}
79     }
80 
81     /**
82      * Repeated calls to next (only accessible via reflection) produce
83      * at least two distinct results, and repeated calls produce all
84      * possible values.
85      */
testNext()86     public void testNext() throws ReflectiveOperationException {
87         // Inhibit "An illegal reflective access operation has occurred"
88         if (!testImplementationDetails) return;
89 
90         ThreadLocalRandom rnd = ThreadLocalRandom.current();
91         final java.lang.reflect.Method m;
92         try {
93             m = ThreadLocalRandom.class.getDeclaredMethod("next", int.class);
94             m.setAccessible(true);
95         } catch (SecurityException acceptable) {
96             // Security manager may deny access
97             return;
98         } catch (Exception ex) {
99             // jdk9 module system may deny access
100             if (ex.getClass().getSimpleName()
101                 .equals("InaccessibleObjectException"))
102                 return;
103             throw ex;
104         }
105 
106         int i;
107         {
108             int val = new java.util.Random().nextInt(4);
109             for (i = 0; i < NCALLS; i++) {
110                 int q = (int) m.invoke(rnd, new Object[] { 2 });
111                 if (val == q) break;
112             }
113             assertTrue(i < NCALLS);
114         }
115 
116         {
117             int r = (int) m.invoke(rnd, new Object[] { 3 });
118             for (i = 0; i < NCALLS; i++) {
119                 int q = (int) m.invoke(rnd, new Object[] { 3 });
120                 assertTrue(q < (1<<3));
121                 if (r != q) break;
122             }
123             assertTrue(i < NCALLS);
124         }
125     }
126 
127     /**
128      * Repeated calls to nextInt produce at least two distinct results
129      */
130     public void testNextInt() {
131         int f = ThreadLocalRandom.current().nextInt();
132         int i = 0;
133         while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
134             ++i;
135         assertTrue(i < NCALLS);
136     }
137 
138     /**
139      * Repeated calls to nextLong produce at least two distinct results
140      */
141     public void testNextLong() {
142         long f = ThreadLocalRandom.current().nextLong();
143         int i = 0;
144         while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
145             ++i;
146         assertTrue(i < NCALLS);
147     }
148 
149     /**
150      * Repeated calls to nextBoolean produce at least two distinct results
151      */
152     public void testNextBoolean() {
153         boolean f = ThreadLocalRandom.current().nextBoolean();
154         int i = 0;
155         while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
156             ++i;
157         assertTrue(i < NCALLS);
158     }
159 
160     /**
161      * Repeated calls to nextFloat produce at least two distinct results
162      */
163     public void testNextFloat() {
164         float f = ThreadLocalRandom.current().nextFloat();
165         int i = 0;
166         while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
167             ++i;
168         assertTrue(i < NCALLS);
169     }
170 
171     /**
172      * Repeated calls to nextDouble produce at least two distinct results
173      */
174     public void testNextDouble() {
175         double f = ThreadLocalRandom.current().nextDouble();
176         int i = 0;
177         while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
178             ++i;
179         assertTrue(i < NCALLS);
180     }
181 
182     /**
183      * Repeated calls to nextGaussian produce at least two distinct results
184      */
185     public void testNextGaussian() {
186         double f = ThreadLocalRandom.current().nextGaussian();
187         int i = 0;
188         while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
189             ++i;
190         assertTrue(i < NCALLS);
191     }
192 
193     /**
194      * nextInt(non-positive) throws IllegalArgumentException
195      */
196     public void testNextIntBoundNonPositive() {
197         ThreadLocalRandom rnd = ThreadLocalRandom.current();
198         for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
199             try {
200                 rnd.nextInt(bound);
201                 shouldThrow();
202             } catch (IllegalArgumentException success) {}
203         }
204     }
205 
206     /**
207      * nextInt(least >= bound) throws IllegalArgumentException
208      */
209     public void testNextIntBadBounds() {
210         int[][] badBoundss = {
211             { 17, 2 },
212             { -42, -42 },
213             { Integer.MAX_VALUE, Integer.MIN_VALUE },
214         };
215         ThreadLocalRandom rnd = ThreadLocalRandom.current();
216         for (int[] badBounds : badBoundss) {
217             try {
218                 rnd.nextInt(badBounds[0], badBounds[1]);
219                 shouldThrow();
220             } catch (IllegalArgumentException success) {}
221         }
222     }
223 
224     /**
225      * nextInt(bound) returns 0 <= value < bound;
226      * repeated calls produce at least two distinct results
227      */
228     public void testNextIntBounded() {
229         // sample bound space across prime number increments
230         for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
231             int f = ThreadLocalRandom.current().nextInt(bound);
232             assertTrue(0 <= f && f < bound);
233             int i = 0;
234             int j;
235             while (i < NCALLS &&
236                    (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
237                 assertTrue(0 <= j && j < bound);
238                 ++i;
239             }
240             assertTrue(i < NCALLS);
241         }
242     }
243 
244     /**
245      * nextInt(least, bound) returns least <= value < bound;
246      * repeated calls produce at least two distinct results
247      */
248     public void testNextIntBounded2() {
249         for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
250             for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
251                 int f = ThreadLocalRandom.current().nextInt(least, bound);
252                 assertTrue(least <= f && f < bound);
253                 int i = 0;
254                 int j;
255                 while (i < NCALLS &&
256                        (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
257                     assertTrue(least <= j && j < bound);
258                     ++i;
259                 }
260                 assertTrue(i < NCALLS);
261             }
262         }
263     }
264 
265     /**
266      * nextLong(non-positive) throws IllegalArgumentException
267      */
268     public void testNextLongBoundNonPositive() {
269         ThreadLocalRandom rnd = ThreadLocalRandom.current();
270         for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
271             try {
272                 rnd.nextLong(bound);
273                 shouldThrow();
274             } catch (IllegalArgumentException success) {}
275         }
276     }
277 
278     /**
279      * nextLong(least >= bound) throws IllegalArgumentException
280      */
281     public void testNextLongBadBounds() {
282         long[][] badBoundss = {
283             { 17L, 2L },
284             { -42L, -42L },
285             { Long.MAX_VALUE, Long.MIN_VALUE },
286         };
287         ThreadLocalRandom rnd = ThreadLocalRandom.current();
288         for (long[] badBounds : badBoundss) {
289             try {
290                 rnd.nextLong(badBounds[0], badBounds[1]);
291                 shouldThrow();
292             } catch (IllegalArgumentException success) {}
293         }
294     }
295 
296     /**
297      * nextLong(bound) returns 0 <= value < bound;
298      * repeated calls produce at least two distinct results
299      */
300     public void testNextLongBounded() {
301         for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
302             long f = ThreadLocalRandom.current().nextLong(bound);
303             assertTrue(0 <= f && f < bound);
304             int i = 0;
305             long j;
306             while (i < NCALLS &&
307                    (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
308                 assertTrue(0 <= j && j < bound);
309                 ++i;
310             }
311             assertTrue(i < NCALLS);
312         }
313     }
314 
315     /**
316      * nextLong(least, bound) returns least <= value < bound;
317      * repeated calls produce at least two distinct results
318      */
319     public void testNextLongBounded2() {
320         for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
321             for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
322                 long f = ThreadLocalRandom.current().nextLong(least, bound);
323                 assertTrue(least <= f && f < bound);
324                 int i = 0;
325                 long j;
326                 while (i < NCALLS &&
327                        (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
328                     assertTrue(least <= j && j < bound);
329                     ++i;
330                 }
331                 assertTrue(i < NCALLS);
332             }
333         }
334     }
335 
336     /**
337      * nextDouble(non-positive) throws IllegalArgumentException
338      */
339     public void testNextDoubleBoundNonPositive() {
340         ThreadLocalRandom rnd = ThreadLocalRandom.current();
341         double[] badBounds = {
342             0.0d,
343             -17.0d,
344             -Double.MIN_VALUE,
345             Double.NEGATIVE_INFINITY,
346             Double.NaN,
347         };
348         for (double bound : badBounds) {
349             try {
350                 rnd.nextDouble(bound);
351                 shouldThrow();
352             } catch (IllegalArgumentException success) {}
353         }
354     }
355 
356     /**
357      * nextDouble(least, bound) returns least <= value < bound;
358      * repeated calls produce at least two distinct results
359      */
360     public void testNextDoubleBounded2() {
361         for (double least = 0.0001; least < 1.0e20; least *= 8) {
362             for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
363                 double f = ThreadLocalRandom.current().nextDouble(least, bound);
364                 assertTrue(least <= f && f < bound);
365                 int i = 0;
366                 double j;
367                 while (i < NCALLS &&
368                        (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
369                     assertTrue(least <= j && j < bound);
370                     ++i;
371                 }
372                 assertTrue(i < NCALLS);
373             }
374         }
375     }
376 
377     /**
378      * Different threads produce different pseudo-random sequences
379      */
380     public void testDifferentSequences() {
381         // Don't use main thread's ThreadLocalRandom - it is likely to
382         // be polluted by previous tests.
383         final AtomicReference<ThreadLocalRandom> threadLocalRandom =
384             new AtomicReference<>();
385         final AtomicLong rand = new AtomicLong();
386 
387         long firstRand = 0;
388         ThreadLocalRandom firstThreadLocalRandom = null;
389 
390         Runnable getRandomState = new CheckedRunnable() {
391             public void realRun() {
392                 ThreadLocalRandom current = ThreadLocalRandom.current();
393                 assertSame(current, ThreadLocalRandom.current());
394                 // test bug: the following is not guaranteed and not true in JDK8
395                 //                assertNotSame(current, threadLocalRandom.get());
396                 rand.set(current.nextLong());
397                 threadLocalRandom.set(current);
398             }};
399 
400         Thread first = newStartedThread(getRandomState);
401         awaitTermination(first);
402         firstRand = rand.get();
403         firstThreadLocalRandom = threadLocalRandom.get();
404 
405         for (int i = 0; i < NCALLS; i++) {
406             Thread t = newStartedThread(getRandomState);
407             awaitTermination(t);
408             if (firstRand != rand.get())
409                 return;
410         }
411         fail("all threads generate the same pseudo-random sequence");
412     }
413 
414     /**
415      * Repeated calls to nextBytes produce at least values of different signs for every byte
416      */
417     public void testNextBytes() {
418         ThreadLocalRandom rnd = ThreadLocalRandom.current();
419         int n = rnd.nextInt(1, 20);
420         byte[] bytes = new byte[n];
421         outer:
422         for (int i = 0; i < n; i++) {
423             for (int tries = NCALLS; tries-->0; ) {
424                 byte before = bytes[i];
425                 rnd.nextBytes(bytes);
426                 byte after = bytes[i];
427                 if (after * before < 0)
428                     continue outer;
429             }
430             fail("not enough variation in random bytes");
431         }
432     }
433 
434     /**
435      * Filling an empty array with random bytes succeeds without effect.
436      */
437     public void testNextBytes_emptyArray() {
438         ThreadLocalRandom.current().nextBytes(new byte[0]);
439     }
440 
441     public void testNextBytes_nullArray() {
442         try {
443             ThreadLocalRandom.current().nextBytes(null);
444             shouldThrow();
445         } catch (NullPointerException success) {}
446     }
447 
448 }
449