Why ThreadLocalRandom Beats Random in Java: Deep Dive into Unsafe and Memory
This article explores the performance drawbacks of java.util.Random in high‑concurrency scenarios, explains how ThreadLocalRandom leverages Unsafe for per‑thread seeds, examines native getLong/putLong operations, and discusses memory layout nuances such as compressed oops and potential pitfalls.
Preface
While writing business code I needed to generate random numbers, so I first considered the JDK Random class. Seeking maximum performance, I turned to ThreadLocalRandom and, while inspecting its implementation, also examined parts of Unsafe, learning many details and solving numerous doubts, which I now summarize.
Random Performance Issues
In typical usage a single Random instance is stored as a field or static variable to avoid repeated construction. This works when thread contention is low, but in a high‑concurrency web service sharing one Random can cause threads to block because Random updates its seed via CAS, leading to repeated CAS failures under contention.
ThreadLocalRandom
The JDK developers addressed this by adding ThreadLocalRandom in the java.util.concurrent package. Although its name suggests a ThreadLocal implementation, the source contains no ThreadLocal fields; instead it relies heavily on Unsafe operations.
Core code snippet:
<code>UNSAFE.putLong(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);</code>
Translated to more familiar Java:
Thread t = Thread.currentThread();
long r = UNSAFE.getLong(t, SEED) + GAMMA;
UNSAFE.putLong(t, SEED, r);The pattern resembles a Map get/set where the current thread object serves as the key and the seed as the value.
Unsafe
Functionality
The relevant native methods are:
public native long getLong(Object obj, long offset);
public native void putLong(Object obj, long offset, long value); putLongwrites a 64‑bit value at the given memory offset of an object, while getLong reads a 64‑bit value from that offset.
Safety Concerns
Because Unsafe can manipulate memory without safety checks, misuse can cause a fatal JVM error. For example:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Test test = new Test();
test.ttt = "12345";
unsafe.putLong(test, 12L, 2333L);
System.out.println(test.value);Running this code triggers a fatal error: the JVM aborts because the memory region originally holding a String is overwritten with a long, corrupting the object header.
ThreadLocalRandom Implementation
ThreadLocalRandomstores a per‑thread seed in the private field threadLocalRandomSeed of the Thread class. The offset of this field is obtained at class‑loading time via:
SEED = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomSeed"));Since the object layout is fixed after class loading, using Unsafe.objectFieldOffset to locate the seed field and then reading/writing it with getLong / putLong is safe and avoids the overhead of accessor methods.
Open Questions
Why Use Unsafe Instead of Get/Set?
Adding public getter/setter methods to Thread would break encapsulation because ThreadLocalRandom resides in a different package. Using Unsafe allows direct memory access without exposing the field.
Memory Layout Details
Investigating object offsets revealed that the sole field value of a test class has an offset of 12 bytes on a 64‑bit JVM with compressed ordinary object pointers (Oops) enabled. The object header occupies 8 bytes (MarkWord), followed by a 4‑byte compressed class pointer, then the field data. Disabling compressed Oops with -XX:-UseCompressedOops changes the offset to 16 bytes.
Conclusion
When writing code, always examine the actual implementation of libraries you depend on; hidden pitfalls like the ones in ThreadLocalRandom and Unsafe can cause subtle bugs. Careful study not only avoids problems but also deepens your understanding of Java internals.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
