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