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 }