Unlocking Java’s Unsafe: Access Low‑Level Memory and Concurrency Safely
This article explains the purpose and risks of Java's sun.misc.Unsafe class, categorizes its APIs, demonstrates how to obtain an Unsafe instance, and provides practical code examples for memory manipulation, CAS operations, thread control, object allocation, and building simple atomic utilities.
Unsafe Introduction
Unsafe, located in the
sun.miscpackage, provides low‑level, potentially unsafe operations such as direct memory access and manual memory management, which can improve Java performance but also increase the risk of pointer‑related bugs.
Many classes in
java.util.concurrent.atomicare implemented using Unsafe.
Unsafe APIs can be grouped into memory operations, CAS, class manipulation, object manipulation, thread control, system information, memory barriers, and array operations.
Memory‑Related Operations
CAS Operations
Atomic classes in
java.util.concurrent.atomicrely on Unsafe.
<code>private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}</code>Thread‑Related Operations
LockSupport uses
parkand
unparkimplemented via Unsafe.
<code>public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}</code>Class‑Related Operations
Object Manipulation
System‑Related Operations
Memory Barriers
loadFence ensures all prior reads complete; storeFence ensures all prior writes complete; fullFence ensures both reads and writes complete.
Java 8’s
StampedLockuses these barriers.
<code>private static final sun.misc.Unsafe U;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
} catch (Exception e) {
throw new Error(e);
}
}
public boolean validate(long stamp) {
U.loadFence();
return (stamp & SBITS) == (state & SBITS);
}</code>U.loadFence();
Unsafe.java Overview
<code>public final class Unsafe {
private static native void registerNatives();
static {
registerNatives();
sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
}
private Unsafe() {}
private static final Unsafe theUnsafe = new Unsafe();
// ...
}</code>Obtaining an Unsafe Instance
Unsafe is a final singleton; the instance can be accessed via reflection:
Method 1
<code>Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);</code>Method 2
<code>private static Unsafe unsafe = null;
static {
try {
Constructor<Unsafe> cons = Unsafe.class.getDeclaredConstructor();
cons.setAccessible(true);
unsafe = cons.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}</code>Simple Unsafe Usage Example
<code>int i = 0;
public static void main(String[] args) throws Exception {
UnsafeDemo d = new UnsafeDemo();
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Field f = UnsafeDemo.class.getDeclaredField("i");
long fieldOffset = unsafe.objectFieldOffset(f);
System.out.println(fieldOffset);
boolean success = unsafe.compareAndSwapInt(d, fieldOffset, 0, 10);
System.out.println(success);
System.out.println(d.i);
}</code>Unsafe Object Operations
<code>private static Unsafe unsafe = null;
static {
try {
Constructor<Unsafe> cons = Unsafe.class.getDeclaredConstructor();
cons.setAccessible(true);
unsafe = cons.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void allocate() {
try {
Person p = (Person) unsafe.allocateInstance(Person.class);
p.setId("s001");
System.out.println(p.getValue());
System.out.println(p.getId());
} catch (Exception e) {
e.printStackTrace();
}
}</code>Result:
Object Operation Example 2
<code>private Person p = new Person("1", "张三");
public static void main(String[] args) throws Exception {
UnSafeObjectDemo d = new UnSafeObjectDemo();
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Field f = d.getClass().getDeclaredField("p");
long offset = unsafe.objectFieldOffset(f);
System.out.println(offset);
boolean res = unsafe.compareAndSwapObject(d, offset, d.p, new Person("2", "李四"));
System.out.println(res);
System.out.println(d.p.getName());
}</code>Creating Objects with Unsafe
When the constructor is unknown or should be bypassed, use reflection factories:
<code>Constructor<Teacher> cons = (Constructor<Teacher>) ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(Teacher.class, Object.class.getConstructor());
cons.setAccessible(true);
Teacher t = cons.newInstance();
System.out.println(t);
</code>Simple Atomic Class Using Unsafe
<code>public class AtomicCount {
private static Unsafe unsafe;
private int value;
private static long valueOffset;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
Field f = AtomicCount.class.getDeclaredField("value");
valueOffset = unsafe.objectFieldOffset(f);
} catch (Exception e) {
e.printStackTrace();
}
}
public AtomicCount(int value) { this.value = value; }
public final int get() { return value; }
public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); }
}</code>End of article.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.