View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  /*
18   * Written by Doug Lea with assistance from members of JCP JSR-166
19   * Expert Group and released to the public domain, as explained at
20   * https://creativecommons.org/publicdomain/zero/1.0/
21   */
22  
23  package io.netty.util.internal;
24  
25  import static io.netty.util.internal.ObjectUtil.checkPositive;
26  
27  import io.netty.util.internal.logging.InternalLogger;
28  import io.netty.util.internal.logging.InternalLoggerFactory;
29  
30  import java.lang.Thread.UncaughtExceptionHandler;
31  import java.security.SecureRandom;
32  import java.util.Random;
33  import java.util.concurrent.BlockingQueue;
34  import java.util.concurrent.LinkedBlockingQueue;
35  import java.util.concurrent.TimeUnit;
36  import java.util.concurrent.atomic.AtomicLong;
37  
38  /**
39   * A random number generator isolated to the current thread.  Like the
40   * global {@link java.util.Random} generator used by the {@link
41   * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
42   * with an internally generated seed that may not otherwise be
43   * modified. When applicable, use of {@code ThreadLocalRandom} rather
44   * than shared {@code Random} objects in concurrent programs will
45   * typically encounter much less overhead and contention.  Use of
46   * {@code ThreadLocalRandom} is particularly appropriate when multiple
47   * tasks (for example, each a {@link io.netty.util.internal.chmv8.ForkJoinTask}) use random numbers
48   * in parallel in thread pools.
49   *
50   * <p>Usages of this class should typically be of the form:
51   * {@code ThreadLocalRandom.current().nextX(...)} (where
52   * {@code X} is {@code Int}, {@code Long}, etc).
53   * When all usages are of this form, it is never possible to
54   * accidently share a {@code ThreadLocalRandom} across multiple threads.
55   *
56   * <p>This class also provides additional commonly used bounded random
57   * generation methods.
58   *
59   * //since 1.7
60   * //author Doug Lea
61   */
62  @SuppressWarnings("all")
63  public final class ThreadLocalRandom extends Random {
64  
65      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ThreadLocalRandom.class);
66  
67      private static final AtomicLong seedUniquifier = new AtomicLong();
68  
69      private static volatile long initialSeedUniquifier;
70  
71      private static final Thread seedGeneratorThread;
72      private static final BlockingQueue<Long> seedQueue;
73      private static final long seedGeneratorStartTime;
74      private static volatile long seedGeneratorEndTime;
75  
76      static {
77          initialSeedUniquifier = SystemPropertyUtil.getLong("io.netty.initialSeedUniquifier", 0);
78          if (initialSeedUniquifier == 0) {
79              boolean secureRandom = SystemPropertyUtil.getBoolean("java.util.secureRandomSeed", false);
80              if (secureRandom) {
81                  seedQueue = new LinkedBlockingQueue<Long>();
82                  seedGeneratorStartTime = System.nanoTime();
83  
84                  // Try to generate a real random number from /dev/random.
85                  // Get from a different thread to avoid blocking indefinitely on a machine without much entropy.
86                  seedGeneratorThread = new Thread("initialSeedUniquifierGenerator") {
87                      @Override
88                      public void run() {
89                          final SecureRandom random = new SecureRandom(); // Get the real random seed from /dev/random
90                          final byte[] seed = random.generateSeed(8);
91                          seedGeneratorEndTime = System.nanoTime();
92                          long s = ((long) seed[0] & 0xff) << 56 |
93                                   ((long) seed[1] & 0xff) << 48 |
94                                   ((long) seed[2] & 0xff) << 40 |
95                                   ((long) seed[3] & 0xff) << 32 |
96                                   ((long) seed[4] & 0xff) << 24 |
97                                   ((long) seed[5] & 0xff) << 16 |
98                                   ((long) seed[6] & 0xff) <<  8 |
99                                   (long) seed[7] & 0xff;
100                         seedQueue.add(s);
101                     }
102                 };
103                 seedGeneratorThread.setDaemon(true);
104                 seedGeneratorThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
105                     @Override
106                     public void uncaughtException(Thread t, Throwable e) {
107                         logger.debug("An exception has been raised by {}", t.getName(), e);
108                     }
109                 });
110                 seedGeneratorThread.start();
111             } else {
112                 initialSeedUniquifier = mix64(System.currentTimeMillis()) ^ mix64(System.nanoTime());
113                 seedGeneratorThread = null;
114                 seedQueue = null;
115                 seedGeneratorStartTime = 0L;
116             }
117         } else {
118             seedGeneratorThread = null;
119             seedQueue = null;
120             seedGeneratorStartTime = 0L;
121         }
122     }
123 
124     public static void setInitialSeedUniquifier(long initialSeedUniquifier) {
125         ThreadLocalRandom.initialSeedUniquifier = initialSeedUniquifier;
126     }
127 
128     public static long getInitialSeedUniquifier() {
129         // Use the value set via the setter.
130         long initialSeedUniquifier = ThreadLocalRandom.initialSeedUniquifier;
131         if (initialSeedUniquifier != 0) {
132             return initialSeedUniquifier;
133         }
134 
135         synchronized (ThreadLocalRandom.class) {
136             initialSeedUniquifier = ThreadLocalRandom.initialSeedUniquifier;
137             if (initialSeedUniquifier != 0) {
138                 return initialSeedUniquifier;
139             }
140 
141             // Get the random seed from the generator thread with timeout.
142             final long timeoutSeconds = 3;
143             final long deadLine = seedGeneratorStartTime + TimeUnit.SECONDS.toNanos(timeoutSeconds);
144             boolean interrupted = false;
145             for (;;) {
146                 final long waitTime = deadLine - System.nanoTime();
147                 try {
148                     final Long seed;
149                     if (waitTime <= 0) {
150                         seed = seedQueue.poll();
151                     } else {
152                         seed = seedQueue.poll(waitTime, TimeUnit.NANOSECONDS);
153                     }
154 
155                     if (seed != null) {
156                         initialSeedUniquifier = seed;
157                         break;
158                     }
159                 } catch (InterruptedException e) {
160                     interrupted = true;
161                     logger.warn("Failed to generate a seed from SecureRandom due to an InterruptedException.");
162                     break;
163                 }
164 
165                 if (waitTime <= 0) {
166                     seedGeneratorThread.interrupt();
167                     logger.warn(
168                             "Failed to generate a seed from SecureRandom within {} seconds. " +
169                             "Not enough entropy?", timeoutSeconds
170                     );
171                     break;
172                 }
173             }
174 
175             // Just in case the initialSeedUniquifier is zero or some other constant
176             initialSeedUniquifier ^= 0x3255ecdc33bae119L; // just a meaningless random number
177             initialSeedUniquifier ^= Long.reverse(System.nanoTime());
178 
179             ThreadLocalRandom.initialSeedUniquifier = initialSeedUniquifier;
180 
181             if (interrupted) {
182                 // Restore the interrupt status because we don't know how to/don't need to handle it here.
183                 Thread.currentThread().interrupt();
184 
185                 // Interrupt the generator thread if it's still running,
186                 // in the hope that the SecureRandom provider raises an exception on interruption.
187                 seedGeneratorThread.interrupt();
188             }
189 
190             if (seedGeneratorEndTime == 0) {
191                 seedGeneratorEndTime = System.nanoTime();
192             }
193 
194             return initialSeedUniquifier;
195         }
196     }
197 
198     private static long newSeed() {
199         for (;;) {
200             final long current = seedUniquifier.get();
201             final long actualCurrent = current != 0? current : getInitialSeedUniquifier();
202 
203             // L'Ecuyer, "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure", 1999
204             final long next = actualCurrent * 181783497276652981L;
205 
206             if (seedUniquifier.compareAndSet(current, next)) {
207                 if (current == 0 && logger.isDebugEnabled()) {
208                     if (seedGeneratorEndTime != 0) {
209                         logger.debug(String.format(
210                                 "-Dio.netty.initialSeedUniquifier: 0x%016x (took %d ms)",
211                                 actualCurrent,
212                                 TimeUnit.NANOSECONDS.toMillis(seedGeneratorEndTime - seedGeneratorStartTime)));
213                     } else {
214                         logger.debug(String.format("-Dio.netty.initialSeedUniquifier: 0x%016x", actualCurrent));
215                     }
216                 }
217                 return next ^ System.nanoTime();
218             }
219         }
220     }
221 
222     // Borrowed from
223     // http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/ThreadLocalRandom.java
224     private static long mix64(long z) {
225         z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
226         z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
227         return z ^ (z >>> 33);
228     }
229 
230     // same constants as Random, but must be redeclared because private
231     private static final long multiplier = 0x5DEECE66DL;
232     private static final long addend = 0xBL;
233     private static final long mask = (1L << 48) - 1;
234 
235     /**
236      * The random seed. We can't use super.seed.
237      */
238     private long rnd;
239 
240     /**
241      * Initialization flag to permit calls to setSeed to succeed only
242      * while executing the Random constructor.  We can't allow others
243      * since it would cause setting seed in one part of a program to
244      * unintentionally impact other usages by the thread.
245      */
246     boolean initialized;
247 
248     // Padding to help avoid memory contention among seed updates in
249     // different TLRs in the common case that they are located near
250     // each other.
251     private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
252 
253     /**
254      * Constructor called only by localRandom.initialValue.
255      */
256     ThreadLocalRandom() {
257         super(newSeed());
258         initialized = true;
259     }
260 
261     /**
262      * Returns the current thread's {@code ThreadLocalRandom}.
263      *
264      * @return the current thread's {@code ThreadLocalRandom}
265      */
266     public static ThreadLocalRandom current() {
267         return InternalThreadLocalMap.get().random();
268     }
269 
270     /**
271      * Throws {@code UnsupportedOperationException}.  Setting seeds in
272      * this generator is not supported.
273      *
274      * @throws UnsupportedOperationException always
275      */
276     @Override
277     public void setSeed(long seed) {
278         if (initialized) {
279             throw new UnsupportedOperationException();
280         }
281         rnd = (seed ^ multiplier) & mask;
282     }
283 
284     @Override
285     protected int next(int bits) {
286         rnd = (rnd * multiplier + addend) & mask;
287         return (int) (rnd >>> (48 - bits));
288     }
289 
290     /**
291      * Returns a pseudorandom, uniformly distributed value between the
292      * given least value (inclusive) and bound (exclusive).
293      *
294      * @param least the least value returned
295      * @param bound the upper bound (exclusive)
296      * @throws IllegalArgumentException if least greater than or equal
297      * to bound
298      * @return the next value
299      */
300     public int nextInt(int least, int bound) {
301         if (least >= bound) {
302             throw new IllegalArgumentException();
303         }
304         return nextInt(bound - least) + least;
305     }
306 
307     /**
308      * Returns a pseudorandom, uniformly distributed value
309      * between 0 (inclusive) and the specified value (exclusive).
310      *
311      * @param n the bound on the random number to be returned.  Must be
312      *        positive.
313      * @return the next value
314      * @throws IllegalArgumentException if n is not positive
315      */
316     public long nextLong(long n) {
317         checkPositive(n, "n");
318 
319         // Divide n by two until small enough for nextInt. On each
320         // iteration (at most 31 of them but usually much less),
321         // randomly choose both whether to include high bit in result
322         // (offset) and whether to continue with the lower vs upper
323         // half (which makes a difference only if odd).
324         long offset = 0;
325         while (n >= Integer.MAX_VALUE) {
326             int bits = next(2);
327             long half = n >>> 1;
328             long nextn = ((bits & 2) == 0) ? half : n - half;
329             if ((bits & 1) == 0) {
330                 offset += n - nextn;
331             }
332             n = nextn;
333         }
334         return offset + nextInt((int) n);
335     }
336 
337     /**
338      * Returns a pseudorandom, uniformly distributed value between the
339      * given least value (inclusive) and bound (exclusive).
340      *
341      * @param least the least value returned
342      * @param bound the upper bound (exclusive)
343      * @return the next value
344      * @throws IllegalArgumentException if least greater than or equal
345      * to bound
346      */
347     public long nextLong(long least, long bound) {
348         if (least >= bound) {
349             throw new IllegalArgumentException();
350         }
351         return nextLong(bound - least) + least;
352     }
353 
354     /**
355      * Returns a pseudorandom, uniformly distributed {@code double} value
356      * between 0 (inclusive) and the specified value (exclusive).
357      *
358      * @param n the bound on the random number to be returned.  Must be
359      *        positive.
360      * @return the next value
361      * @throws IllegalArgumentException if n is not positive
362      */
363     public double nextDouble(double n) {
364         checkPositive(n, "n");
365         return nextDouble() * n;
366     }
367 
368     /**
369      * Returns a pseudorandom, uniformly distributed value between the
370      * given least value (inclusive) and bound (exclusive).
371      *
372      * @param least the least value returned
373      * @param bound the upper bound (exclusive)
374      * @return the next value
375      * @throws IllegalArgumentException if least greater than or equal
376      * to bound
377      */
378     public double nextDouble(double least, double bound) {
379         if (least >= bound) {
380             throw new IllegalArgumentException();
381         }
382         return nextDouble() * (bound - least) + least;
383     }
384 
385     private static final long serialVersionUID = -5851777807851030925L;
386 }