ThreadLocalRandomTest.java revision 16376:584f92dadf6b
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
34import java.util.concurrent.ThreadLocalRandom;
35import java.util.concurrent.atomic.AtomicLong;
36import java.util.concurrent.atomic.AtomicReference;
37
38import junit.framework.Test;
39import junit.framework.TestSuite;
40
41public class ThreadLocalRandomTest extends JSR166TestCase {
42
43    public static void main(String[] args) {
44        main(suite(), args);
45    }
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     */
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     */
86    public void testNext() throws ReflectiveOperationException {
87        ThreadLocalRandom rnd = ThreadLocalRandom.current();
88        final java.lang.reflect.Method m;
89        try {
90            m = ThreadLocalRandom.class.getDeclaredMethod(
91                    "next", new Class[] { int.class });
92            m.setAccessible(true);
93        } catch (SecurityException acceptable) {
94            // Security manager may deny access
95            return;
96        } catch (Exception ex) {
97            // jdk9 module system may deny access
98            if (ex.getClass().getSimpleName()
99                .equals("InaccessibleObjectException"))
100                return;
101            throw ex;
102        }
103
104        int i;
105        {
106            int val = new java.util.Random().nextInt(4);
107            for (i = 0; i < NCALLS; i++) {
108                int q = (int) m.invoke(rnd, new Object[] { 2 });
109                if (val == q) break;
110            }
111            assertTrue(i < NCALLS);
112        }
113
114        {
115            int r = (int) m.invoke(rnd, new Object[] { 3 });
116            for (i = 0; i < NCALLS; i++) {
117                int q = (int) m.invoke(rnd, new Object[] { 3 });
118                assertTrue(q < (1<<3));
119                if (r != q) break;
120            }
121            assertTrue(i < NCALLS);
122        }
123    }
124
125    /**
126     * Repeated calls to nextInt produce at least two distinct results
127     */
128    public void testNextInt() {
129        int f = ThreadLocalRandom.current().nextInt();
130        int i = 0;
131        while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
132            ++i;
133        assertTrue(i < NCALLS);
134    }
135
136    /**
137     * Repeated calls to nextLong produce at least two distinct results
138     */
139    public void testNextLong() {
140        long f = ThreadLocalRandom.current().nextLong();
141        int i = 0;
142        while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
143            ++i;
144        assertTrue(i < NCALLS);
145    }
146
147    /**
148     * Repeated calls to nextBoolean produce at least two distinct results
149     */
150    public void testNextBoolean() {
151        boolean f = ThreadLocalRandom.current().nextBoolean();
152        int i = 0;
153        while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
154            ++i;
155        assertTrue(i < NCALLS);
156    }
157
158    /**
159     * Repeated calls to nextFloat produce at least two distinct results
160     */
161    public void testNextFloat() {
162        float f = ThreadLocalRandom.current().nextFloat();
163        int i = 0;
164        while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
165            ++i;
166        assertTrue(i < NCALLS);
167    }
168
169    /**
170     * Repeated calls to nextDouble produce at least two distinct results
171     */
172    public void testNextDouble() {
173        double f = ThreadLocalRandom.current().nextDouble();
174        int i = 0;
175        while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
176            ++i;
177        assertTrue(i < NCALLS);
178    }
179
180    /**
181     * Repeated calls to nextGaussian produce at least two distinct results
182     */
183    public void testNextGaussian() {
184        double f = ThreadLocalRandom.current().nextGaussian();
185        int i = 0;
186        while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
187            ++i;
188        assertTrue(i < NCALLS);
189    }
190
191    /**
192     * nextInt(non-positive) throws IllegalArgumentException
193     */
194    public void testNextIntBoundNonPositive() {
195        ThreadLocalRandom rnd = ThreadLocalRandom.current();
196        for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
197            try {
198                rnd.nextInt(bound);
199                shouldThrow();
200            } catch (IllegalArgumentException success) {}
201        }
202    }
203
204    /**
205     * nextInt(least >= bound) throws IllegalArgumentException
206     */
207    public void testNextIntBadBounds() {
208        int[][] badBoundss = {
209            { 17, 2 },
210            { -42, -42 },
211            { Integer.MAX_VALUE, Integer.MIN_VALUE },
212        };
213        ThreadLocalRandom rnd = ThreadLocalRandom.current();
214        for (int[] badBounds : badBoundss) {
215            try {
216                rnd.nextInt(badBounds[0], badBounds[1]);
217                shouldThrow();
218            } catch (IllegalArgumentException success) {}
219        }
220    }
221
222    /**
223     * nextInt(bound) returns 0 <= value < bound;
224     * repeated calls produce at least two distinct results
225     */
226    public void testNextIntBounded() {
227        // sample bound space across prime number increments
228        for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
229            int f = ThreadLocalRandom.current().nextInt(bound);
230            assertTrue(0 <= f && f < bound);
231            int i = 0;
232            int j;
233            while (i < NCALLS &&
234                   (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
235                assertTrue(0 <= j && j < bound);
236                ++i;
237            }
238            assertTrue(i < NCALLS);
239        }
240    }
241
242    /**
243     * nextInt(least, bound) returns least <= value < bound;
244     * repeated calls produce at least two distinct results
245     */
246    public void testNextIntBounded2() {
247        for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
248            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
249                int f = ThreadLocalRandom.current().nextInt(least, bound);
250                assertTrue(least <= f && f < bound);
251                int i = 0;
252                int j;
253                while (i < NCALLS &&
254                       (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
255                    assertTrue(least <= j && j < bound);
256                    ++i;
257                }
258                assertTrue(i < NCALLS);
259            }
260        }
261    }
262
263    /**
264     * nextLong(non-positive) throws IllegalArgumentException
265     */
266    public void testNextLongBoundNonPositive() {
267        ThreadLocalRandom rnd = ThreadLocalRandom.current();
268        for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
269            try {
270                rnd.nextLong(bound);
271                shouldThrow();
272            } catch (IllegalArgumentException success) {}
273        }
274    }
275
276    /**
277     * nextLong(least >= bound) throws IllegalArgumentException
278     */
279    public void testNextLongBadBounds() {
280        long[][] badBoundss = {
281            { 17L, 2L },
282            { -42L, -42L },
283            { Long.MAX_VALUE, Long.MIN_VALUE },
284        };
285        ThreadLocalRandom rnd = ThreadLocalRandom.current();
286        for (long[] badBounds : badBoundss) {
287            try {
288                rnd.nextLong(badBounds[0], badBounds[1]);
289                shouldThrow();
290            } catch (IllegalArgumentException success) {}
291        }
292    }
293
294    /**
295     * nextLong(bound) returns 0 <= value < bound;
296     * repeated calls produce at least two distinct results
297     */
298    public void testNextLongBounded() {
299        for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
300            long f = ThreadLocalRandom.current().nextLong(bound);
301            assertTrue(0 <= f && f < bound);
302            int i = 0;
303            long j;
304            while (i < NCALLS &&
305                   (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
306                assertTrue(0 <= j && j < bound);
307                ++i;
308            }
309            assertTrue(i < NCALLS);
310        }
311    }
312
313    /**
314     * nextLong(least, bound) returns least <= value < bound;
315     * repeated calls produce at least two distinct results
316     */
317    public void testNextLongBounded2() {
318        for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
319            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
320                long f = ThreadLocalRandom.current().nextLong(least, bound);
321                assertTrue(least <= f && f < bound);
322                int i = 0;
323                long j;
324                while (i < NCALLS &&
325                       (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
326                    assertTrue(least <= j && j < bound);
327                    ++i;
328                }
329                assertTrue(i < NCALLS);
330            }
331        }
332    }
333
334    /**
335     * nextDouble(non-positive) throws IllegalArgumentException
336     */
337    public void testNextDoubleBoundNonPositive() {
338        ThreadLocalRandom rnd = ThreadLocalRandom.current();
339        double[] badBounds = {
340            0.0d,
341            -17.0d,
342            -Double.MIN_VALUE,
343            Double.NEGATIVE_INFINITY,
344            Double.NaN,
345        };
346        for (double bound : badBounds) {
347            try {
348                rnd.nextDouble(bound);
349                shouldThrow();
350            } catch (IllegalArgumentException success) {}
351        }
352    }
353
354    /**
355     * nextDouble(least, bound) returns least <= value < bound;
356     * repeated calls produce at least two distinct results
357     */
358    public void testNextDoubleBounded2() {
359        for (double least = 0.0001; least < 1.0e20; least *= 8) {
360            for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
361                double f = ThreadLocalRandom.current().nextDouble(least, bound);
362                assertTrue(least <= f && f < bound);
363                int i = 0;
364                double j;
365                while (i < NCALLS &&
366                       (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
367                    assertTrue(least <= j && j < bound);
368                    ++i;
369                }
370                assertTrue(i < NCALLS);
371            }
372        }
373    }
374
375    /**
376     * Different threads produce different pseudo-random sequences
377     */
378    public void testDifferentSequences() {
379        // Don't use main thread's ThreadLocalRandom - it is likely to
380        // be polluted by previous tests.
381        final AtomicReference<ThreadLocalRandom> threadLocalRandom =
382            new AtomicReference<ThreadLocalRandom>();
383        final AtomicLong rand = new AtomicLong();
384
385        long firstRand = 0;
386        ThreadLocalRandom firstThreadLocalRandom = null;
387
388        Runnable getRandomState = new CheckedRunnable() {
389            public void realRun() {
390                ThreadLocalRandom current = ThreadLocalRandom.current();
391                assertSame(current, ThreadLocalRandom.current());
392                // test bug: the following is not guaranteed and not true in JDK8
393                //                assertNotSame(current, threadLocalRandom.get());
394                rand.set(current.nextLong());
395                threadLocalRandom.set(current);
396            }};
397
398        Thread first = newStartedThread(getRandomState);
399        awaitTermination(first);
400        firstRand = rand.get();
401        firstThreadLocalRandom = threadLocalRandom.get();
402
403        for (int i = 0; i < NCALLS; i++) {
404            Thread t = newStartedThread(getRandomState);
405            awaitTermination(t);
406            if (firstRand != rand.get())
407                return;
408        }
409        fail("all threads generate the same pseudo-random sequence");
410    }
411
412}
413