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 
  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         // 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         Runnable getRandomState = new CheckedRunnable() {
 388             public void realRun() {
 389                 ThreadLocalRandom current = ThreadLocalRandom.current();
 390                 assertSame(current, ThreadLocalRandom.current());
 391                 rand.set(current.nextLong());
 392                 threadLocalRandom.set(current);
 393             }};
 394 
 395         awaitTermination(newStartedThread(getRandomState));
 396         long firstRand = rand.get();
 397         ThreadLocalRandom firstThreadLocalRandom = threadLocalRandom.get();
 398         assertNotNull(firstThreadLocalRandom);
 399 
 400         for (int i = 0; i < NCALLS; i++) {
 401             awaitTermination(newStartedThread(getRandomState));
 402             if (testImplementationDetails)
 403                 // ThreadLocalRandom has been a singleton since jdk8.
 404                 assertSame(firstThreadLocalRandom, threadLocalRandom.get());
 405             if (firstRand != rand.get())
 406                 return;
 407         }
 408         fail("all threads generate the same pseudo-random sequence");
 409     }
 410 
 411     /**
 412      * Repeated calls to nextBytes produce at least values of different signs for every byte
 413      */
 414     public void testNextBytes() {
 415         ThreadLocalRandom rnd = ThreadLocalRandom.current();
 416         int n = rnd.nextInt(1, 20);
 417         byte[] bytes = new byte[n];
 418         outer:
 419         for (int i = 0; i < n; i++) {
 420             for (int tries = NCALLS; tries-->0; ) {
 421                 byte before = bytes[i];
 422                 rnd.nextBytes(bytes);
 423                 byte after = bytes[i];
 424                 if (after * before < 0)
 425                     continue outer;
 426             }
 427             fail("not enough variation in random bytes");
 428         }
 429     }
 430 
 431     /**
 432      * Filling an empty array with random bytes succeeds without effect.
 433      */
 434     public void testNextBytes_emptyArray() {
 435         ThreadLocalRandom.current().nextBytes(new byte[0]);
 436     }
 437 
 438     public void testNextBytes_nullArray() {
 439         try {
 440             ThreadLocalRandom.current().nextBytes(null);
 441             shouldThrow();
 442         } catch (NullPointerException success) {}
 443     }
 444 
 445 }