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