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