1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 */ 6 7 package jsr166; 8 9 import junit.framework.*; 10 import java.util.*; 11 import java.util.concurrent.ThreadLocalRandom; 12 import java.util.concurrent.atomic.AtomicLong; 13 import java.util.concurrent.atomic.AtomicReference; 14 15 public class ThreadLocalRandomTest extends JSR166TestCase { 16 17 /* 18 * Testing coverage notes: 19 * 20 * We don't test randomness properties, but only that repeated 21 * calls, up to NCALLS tries, produce at least one different 22 * result. For bounded versions, we sample various intervals 23 * across multiples of primes. 24 */ 25 26 // 27 static final int NCALLS = 10000; 28 29 // max sampled int bound 30 static final int MAX_INT_BOUND = (1 << 28); 31 32 // Max sampled long bound 33 static final long MAX_LONG_BOUND = (1L << 42); 34 35 /** 36 * setSeed throws UnsupportedOperationException 37 */ testSetSeed()38 public void testSetSeed() { 39 try { 40 ThreadLocalRandom.current().setSeed(17); 41 shouldThrow(); 42 } catch (UnsupportedOperationException success) {} 43 } 44 45 /** 46 * Repeated calls to nextInt produce at least one different result 47 */ testNextInt()48 public void testNextInt() { 49 int f = ThreadLocalRandom.current().nextInt(); 50 int i = 0; 51 while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f) 52 ++i; 53 assertTrue(i < NCALLS); 54 } 55 56 /** 57 * Repeated calls to nextLong produce at least one different result 58 */ 59 public void testNextLong() { 60 long f = ThreadLocalRandom.current().nextLong(); 61 int i = 0; 62 while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f) 63 ++i; 64 assertTrue(i < NCALLS); 65 } 66 67 /** 68 * Repeated calls to nextBoolean produce at least one different result 69 */ 70 public void testNextBoolean() { 71 boolean f = ThreadLocalRandom.current().nextBoolean(); 72 int i = 0; 73 while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f) 74 ++i; 75 assertTrue(i < NCALLS); 76 } 77 78 /** 79 * Repeated calls to nextFloat produce at least one different result 80 */ 81 public void testNextFloat() { 82 float f = ThreadLocalRandom.current().nextFloat(); 83 int i = 0; 84 while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f) 85 ++i; 86 assertTrue(i < NCALLS); 87 } 88 89 /** 90 * Repeated calls to nextDouble produce at least one different result 91 */ 92 public void testNextDouble() { 93 double f = ThreadLocalRandom.current().nextDouble(); 94 double i = 0; 95 while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f) 96 ++i; 97 assertTrue(i < NCALLS); 98 } 99 100 /** 101 * Repeated calls to nextGaussian produce at least one different result 102 */ 103 public void testNextGaussian() { 104 double f = ThreadLocalRandom.current().nextGaussian(); 105 int i = 0; 106 while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f) 107 ++i; 108 assertTrue(i < NCALLS); 109 } 110 111 /** 112 * nextInt(negative) throws IllegalArgumentException; 113 */ 114 public void testNextIntBoundedNeg() { 115 try { 116 int f = ThreadLocalRandom.current().nextInt(-17); 117 shouldThrow(); 118 } catch (IllegalArgumentException success) {} 119 } 120 121 /** 122 * nextInt(least >= bound) throws IllegalArgumentException; 123 */ 124 public void testNextIntBadBounds() { 125 try { 126 int f = ThreadLocalRandom.current().nextInt(17, 2); 127 shouldThrow(); 128 } catch (IllegalArgumentException success) {} 129 } 130 131 /** 132 * nextInt(bound) returns 0 <= value < bound; 133 * repeated calls produce at least one different result 134 */ 135 public void testNextIntBounded() { 136 // sample bound space across prime number increments 137 for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { 138 int f = ThreadLocalRandom.current().nextInt(bound); 139 assertTrue(0 <= f && f < bound); 140 int i = 0; 141 int j; 142 while (i < NCALLS && 143 (j = ThreadLocalRandom.current().nextInt(bound)) == f) { 144 assertTrue(0 <= j && j < bound); 145 ++i; 146 } 147 assertTrue(i < NCALLS); 148 } 149 } 150 151 /** 152 * nextInt(least, bound) returns least <= value < bound; 153 * repeated calls produce at least one different result 154 */ 155 public void testNextIntBounded2() { 156 for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { 157 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { 158 int f = ThreadLocalRandom.current().nextInt(least, bound); 159 assertTrue(least <= f && f < bound); 160 int i = 0; 161 int j; 162 while (i < NCALLS && 163 (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) { 164 assertTrue(least <= j && j < bound); 165 ++i; 166 } 167 assertTrue(i < NCALLS); 168 } 169 } 170 } 171 172 /** 173 * nextLong(negative) throws IllegalArgumentException; 174 */ 175 public void testNextLongBoundedNeg() { 176 try { 177 long f = ThreadLocalRandom.current().nextLong(-17); 178 shouldThrow(); 179 } catch (IllegalArgumentException success) {} 180 } 181 182 /** 183 * nextLong(least >= bound) throws IllegalArgumentException; 184 */ 185 public void testNextLongBadBounds() { 186 try { 187 long f = ThreadLocalRandom.current().nextLong(17, 2); 188 shouldThrow(); 189 } catch (IllegalArgumentException success) {} 190 } 191 192 /** 193 * nextLong(bound) returns 0 <= value < bound; 194 * repeated calls produce at least one different result 195 */ 196 public void testNextLongBounded() { 197 for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { 198 long f = ThreadLocalRandom.current().nextLong(bound); 199 assertTrue(0 <= f && f < bound); 200 int i = 0; 201 long j; 202 while (i < NCALLS && 203 (j = ThreadLocalRandom.current().nextLong(bound)) == f) { 204 assertTrue(0 <= j && j < bound); 205 ++i; 206 } 207 assertTrue(i < NCALLS); 208 } 209 } 210 211 /** 212 * nextLong(least, bound) returns least <= value < bound; 213 * repeated calls produce at least one different result 214 */ 215 public void testNextLongBounded2() { 216 for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { 217 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { 218 long f = ThreadLocalRandom.current().nextLong(least, bound); 219 assertTrue(least <= f && f < bound); 220 int i = 0; 221 long j; 222 while (i < NCALLS && 223 (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) { 224 assertTrue(least <= j && j < bound); 225 ++i; 226 } 227 assertTrue(i < NCALLS); 228 } 229 } 230 } 231 232 /** 233 * nextDouble(least, bound) returns least <= value < bound; 234 * repeated calls produce at least one different result 235 */ 236 public void testNextDoubleBounded2() { 237 for (double least = 0.0001; least < 1.0e20; least *= 8) { 238 for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { 239 double f = ThreadLocalRandom.current().nextDouble(least, bound); 240 assertTrue(least <= f && f < bound); 241 int i = 0; 242 double j; 243 while (i < NCALLS && 244 (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) { 245 assertTrue(least <= j && j < bound); 246 ++i; 247 } 248 assertTrue(i < NCALLS); 249 } 250 } 251 } 252 253 /** 254 * Different threads produce different pseudo-random sequences 255 */ 256 public void testDifferentSequences() { 257 // Don't use main thread's ThreadLocalRandom - it is likely to 258 // be polluted by previous tests. 259 final AtomicReference<ThreadLocalRandom> threadLocalRandom = 260 new AtomicReference<ThreadLocalRandom>(); 261 final AtomicLong rand = new AtomicLong(); 262 263 long firstRand = 0; 264 ThreadLocalRandom firstThreadLocalRandom = null; 265 266 final CheckedRunnable getRandomState = new CheckedRunnable() { 267 public void realRun() { 268 ThreadLocalRandom current = ThreadLocalRandom.current(); 269 assertSame(current, ThreadLocalRandom.current()); 270 // test bug: the following is not guaranteed and not true in JDK8 271 // assertNotSame(current, threadLocalRandom.get()); 272 rand.set(current.nextLong()); 273 threadLocalRandom.set(current); 274 }}; 275 276 Thread first = newStartedThread(getRandomState); 277 awaitTermination(first); 278 firstRand = rand.get(); 279 firstThreadLocalRandom = threadLocalRandom.get(); 280 281 for (int i = 0; i < NCALLS; i++) { 282 Thread t = newStartedThread(getRandomState); 283 awaitTermination(t); 284 if (firstRand != rand.get()) 285 return; 286 } 287 fail("all threads generate the same pseudo-random sequence"); 288 } 289 290 } 291