22 * Written by Doug Lea with assistance from members of JCP JSR-166
33 * Expert Group and released to the public domain, as explained at
44 * http://creativecommons.org/publicdomain/zero/1.0/
5+ *
6+ * Source: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.10
57 */
68
79package io .prometheus .client ;
10+
811import java .util .Random ;
912
1013/**
@@ -40,7 +43,7 @@ abstract class Striped64 extends Number {
4043 *
4144 * A single spinlock ("busy") is used for initializing and
4245 * resizing the table, as well as populating slots with new Cells.
43- * There is no need for a blocking lock: When the lock is not
46+ * There is no need for a blocking lock; when the lock is not
4447 * available, threads try other slots (or the base). During these
4548 * retries, there is increased contention and reduced locality,
4649 * which is still better than alternatives.
@@ -102,7 +105,7 @@ final boolean cas(long cmp, long val) {
102105 UNSAFE = getUnsafe ();
103106 Class <?> ak = Cell .class ;
104107 valueOffset = UNSAFE .objectFieldOffset
105- (ak .getDeclaredField ("value" ));
108+ (ak .getDeclaredField ("value" ));
106109 } catch (Exception e ) {
107110 throw new Error (e );
108111 }
@@ -111,32 +114,17 @@ final boolean cas(long cmp, long val) {
111114 }
112115
113116 /**
114- * Holder for the thread-local hash code. The code is initially
115- * random, but may be set to a different value upon collisions.
117+ * ThreadLocal holding a single-slot int array holding hash code.
118+ * Unlike the JDK8 version of this class, we use a suboptimal
119+ * int[] representation to avoid introducing a new type that can
120+ * impede class-unloading when ThreadLocals are not removed.
116121 */
117- static final class HashCode {
118- static final Random rng = new Random ();
119- int code ;
120- HashCode () {
121- int h = rng .nextInt (); // Avoid zero to allow xorShift rehash
122- code = (h == 0 ) ? 1 : h ;
123- }
124- }
125-
126- /**
127- * The corresponding ThreadLocal class
128- */
129- static final class ThreadHashCode extends ThreadLocal <HashCode > {
130- public HashCode initialValue () { return new HashCode (); }
131- }
122+ static final ThreadLocal <int []> threadHashCode = new ThreadLocal <int []>();
132123
133124 /**
134- * Static per-thread hash codes. Shared across all instances to
135- * reduce ThreadLocal pollution and because adjustments due to
136- * collisions in one table are likely to be appropriate for
137- * others.
125+ * Generator of new random hash codes
138126 */
139- static final ThreadHashCode threadHashCode = new ThreadHashCode ();
127+ static final Random rng = new Random ();
140128
141129 /** Number of CPUS, to place bound on table size */
142130 static final int NCPU = Runtime .getRuntime ().availableProcessors ();
@@ -199,8 +187,15 @@ final boolean casBusy() {
199187 * @param hc the hash code holder
200188 * @param wasUncontended false if CAS failed before call
201189 */
202- final void retryUpdate (long x , HashCode hc , boolean wasUncontended ) {
203- int h = hc .code ;
190+ final void retryUpdate (long x , int [] hc , boolean wasUncontended ) {
191+ int h ;
192+ if (hc == null ) {
193+ threadHashCode .set (hc = new int [1 ]); // Initialize randomly
194+ int r = rng .nextInt (); // Avoid zero to allow xorShift rehash
195+ h = hc [0 ] = (r == 0 ) ? 1 : r ;
196+ }
197+ else
198+ h = hc [0 ];
204199 boolean collide = false ; // True if last slot nonempty
205200 for (;;) {
206201 Cell [] as ; Cell a ; int n ; long v ;
@@ -213,8 +208,8 @@ final void retryUpdate(long x, HashCode hc, boolean wasUncontended) {
213208 try { // Recheck under lock
214209 Cell [] rs ; int m , j ;
215210 if ((rs = cells ) != null &&
216- (m = rs .length ) > 0 &&
217- rs [j = (m - 1 ) & h ] == null ) {
211+ (m = rs .length ) > 0 &&
212+ rs [j = (m - 1 ) & h ] == null ) {
218213 rs [j ] = r ;
219214 created = true ;
220215 }
@@ -253,6 +248,7 @@ else if (busy == 0 && casBusy()) {
253248 h ^= h << 13 ; // Rehash
254249 h ^= h >>> 17 ;
255250 h ^= h << 5 ;
251+ hc [0 ] = h ; // Record index for next time
256252 }
257253 else if (busy == 0 && cells == as && casBusy ()) {
258254 boolean init = false ;
@@ -272,7 +268,6 @@ else if (busy == 0 && cells == as && casBusy()) {
272268 else if (casBase (v = base , fn (v , x )))
273269 break ; // Fall back on using base
274270 }
275- hc .code = h ; // Record index for next time
276271 }
277272
278273
@@ -301,9 +296,9 @@ final void internalReset(long initialValue) {
301296 UNSAFE = getUnsafe ();
302297 Class <?> sk = Striped64 .class ;
303298 baseOffset = UNSAFE .objectFieldOffset
304- (sk .getDeclaredField ("base" ));
299+ (sk .getDeclaredField ("base" ));
305300 busyOffset = UNSAFE .objectFieldOffset
306- (sk .getDeclaredField ("busy" ));
301+ (sk .getDeclaredField ("busy" ));
307302 } catch (Exception e ) {
308303 throw new Error (e );
309304 }
@@ -319,22 +314,23 @@ final void internalReset(long initialValue) {
319314 private static sun .misc .Unsafe getUnsafe () {
320315 try {
321316 return sun .misc .Unsafe .getUnsafe ();
322- } catch (SecurityException se ) {
323- try {
324- return java .security .AccessController .doPrivileged
325- (new java .security
326- .PrivilegedExceptionAction <sun .misc .Unsafe >() {
317+ } catch (SecurityException tryReflectionInstead ) {}
318+ try {
319+ return java .security .AccessController .doPrivileged
320+ (new java .security .PrivilegedExceptionAction <sun .misc .Unsafe >() {
327321 public sun .misc .Unsafe run () throws Exception {
328- java .lang .reflect .Field f = sun .misc
329- .Unsafe .class .getDeclaredField ("theUnsafe" );
330- f .setAccessible (true );
331- return (sun .misc .Unsafe ) f .get (null );
322+ Class <sun .misc .Unsafe > k = sun .misc .Unsafe .class ;
323+ for (java .lang .reflect .Field f : k .getDeclaredFields ()) {
324+ f .setAccessible (true );
325+ Object x = f .get (null );
326+ if (k .isInstance (x ))
327+ return k .cast (x );
328+ }
329+ throw new NoSuchFieldError ("the Unsafe" );
332330 }});
333- } catch (java .security .PrivilegedActionException e ) {
334- throw new RuntimeException ("Could not initialize intrinsics" ,
335- e .getCause ());
336- }
331+ } catch (java .security .PrivilegedActionException e ) {
332+ throw new RuntimeException ("Could not initialize intrinsics" ,
333+ e .getCause ());
337334 }
338335 }
339-
340336}
0 commit comments