1 modulehunt.concurrency.ThreadLocalRandom;
2 3 importhunt.concurrency.atomic.AtomicHelper;
4 importhunt.util.DateTime;
5 importstd.datetime : Clock;
6 7 8 /**
9 * A random number generator isolated to the current thread. Like the
10 * global {@link java.util.Random} generator used by the {@link
11 * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
12 * with an internally generated seed that may not otherwise be
13 * modified. When applicable, use of {@code ThreadLocalRandom} rather
14 * than shared {@code Random} objects in concurrent programs will
15 * typically encounter much less overhead and contention. Use of
16 * {@code ThreadLocalRandom} is particularly appropriate when multiple
17 * tasks (for example, each a {@link ForkJoinTask}) use random numbers
18 * in parallel in thread pools.
19 *
20 * <p>Usages of this class should typically be of the form:
21 * {@code ThreadLocalRandom.current().nextX(...)} (where
22 * {@code X} is {@code Int}, {@code Long}, etc).
23 * When all usages are of this form, it is never possible to
24 * accidentally share a {@code ThreadLocalRandom} across multiple threads.
25 *
26 * <p>This class also provides additional commonly used bounded random
27 * generation methods.
28 *
29 * <p>Instances of {@code ThreadLocalRandom} are not cryptographically
30 * secure. Consider instead using {@link java.security.SecureRandom}
31 * in security-sensitive applications. Additionally,
32 * default-constructed instances do not use a cryptographically random
33 * seed unless the {@linkplain System#getProperty system property}
34 * {@code java.util.secureRandomSeed} is set to {@code true}.
35 *
36 * @author Doug Lea
37 */38 classThreadLocalRandom {
39 // These fields are used to build the high-performance PRNGs in the40 // concurrent code, and we can not risk accidental false sharing. 41 /** The current seed for a ThreadLocalRandom */42 staticlongthreadLocalRandomSeed = 0;
43 44 /** Probe hash value; nonzero if threadLocalRandomSeed initialized */45 staticintthreadLocalRandomProbe = 0;
46 47 /** Secondary seed isolated from public ThreadLocalRandom sequence */48 staticintthreadLocalRandomSecondarySeed = 0;
49 50 staticsharedlongseeder = 0;
51 52 /** Generates per-thread initialization/probe field */53 privatestaticsharedintprobeGenerator = 0;
54 55 /**
56 * The seed increment.
57 */58 privateenumlongGAMMA = 0x9e3779b97f4a7c15L;
59 60 /**
61 * The increment for generating probe values.
62 */63 privateenumintPROBE_INCREMENT = 0x9e3779b9;
64 65 /**
66 * The increment of seeder per new instance.
67 */68 privateenumlongSEEDER_INCREMENT = 0xbb67ae8584caa73bL;
69 70 /**
71 * The least non-zero value returned by nextDouble(). This value
72 * is scaled by a random value of 53 bits to produce a result.
73 */74 privateenumdoubleDOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)75 privateenumfloatFLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)76 77 // IllegalArgumentException messages78 enumstringBAD_BOUND = "bound must be positive";
79 enumstringBAD_RANGE = "bound must be greater than origin";
80 enumstringBAD_SIZE = "size must be non-negative";
81 82 sharedstaticthis() {
83 seeder = mix64(DateTime.currentTimeMillis()) ^
84 mix64(Clock.currStdTime()*100);
85 }
86 87 privatestaticlongmix64(longz) {
88 z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
89 z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
90 returnz ^ (z >>> 33);
91 }
92 93 privatestaticintmix32(longz) {
94 z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
95 returncast(int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
96 }
97 98 /**
99 * Initialize Thread fields for the current thread. Called only
100 * when Thread.threadLocalRandomProbe is zero, indicating that a
101 * thread local seed value needs to be generated. Note that even
102 * though the initialization is purely thread-local, we need to
103 * rely on (static) atomic generators to initialize the values.
104 */105 staticfinalvoidlocalInit() {
106 intp = AtomicHelper.increment(probeGenerator, PROBE_INCREMENT);
107 intprobe = (p == 0) ? 1 : p; // skip 0108 longseed = mix64(AtomicHelper.getAndAdd(seeder, SEEDER_INCREMENT));
109 threadLocalRandomSeed = seed;
110 threadLocalRandomProbe = probe;
111 }
112 113 /**
114 * Returns the probe value for the current thread without forcing
115 * initialization. Note that invoking ThreadLocalRandom.current()
116 * can be used to force initialization on zero return.
117 */118 staticintgetProbe() {
119 returnthreadLocalRandomProbe;
120 }
121 122 /**
123 * Pseudo-randomly advances and records the given probe value for the
124 * given thread.
125 */126 staticintadvanceProbe(intprobe) {
127 probe ^= probe << 13; // xorshift128 probe ^= probe >>> 17;
129 probe ^= probe << 5;
130 threadLocalRandomProbe = probe;
131 returnprobe;
132 }
133 134 /**
135 * Returns the pseudo-randomly initialized or updated secondary seed.
136 */137 staticintnextSecondarySeed() {
138 intr;
139 if ((r = threadLocalRandomSecondarySeed) != 0) {
140 r ^= r << 13; // xorshift141 r ^= r >>> 17;
142 r ^= r << 5;
143 }
144 elseif ((r = mix32(AtomicHelper.getAndAdd(seeder, SEEDER_INCREMENT))) == 0)
145 r = 1; // avoid zero146 threadLocalRandomSecondarySeed = r;
147 returnr;
148 }
149 }