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.misc package, 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.atomic are 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.atomic rely on Unsafe.
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);
}Thread‑Related Operations
LockSupport uses park and unpark implemented via Unsafe.
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);
}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 StampedLock uses these barriers.
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);
}U.loadFence();
Unsafe.java Overview
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();
// ...
}Obtaining an Unsafe Instance
Unsafe is a final singleton; the instance can be accessed via reflection:
Method 1
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);Method 2
private static Unsafe unsafe = null;
static {
try {
Constructor<Unsafe> cons = Unsafe.class.getDeclaredConstructor();
cons.setAccessible(true);
unsafe = cons.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}Simple Unsafe Usage Example
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);
}Unsafe Object Operations
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();
}
}Result:
Object Operation Example 2
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());
}Creating Objects with Unsafe
When the constructor is unknown or should be bypassed, use reflection factories:
Constructor<Teacher> cons = (Constructor<Teacher>) ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(Teacher.class, Object.class.getConstructor());
cons.setAccessible(true);
Teacher t = cons.newInstance();
System.out.println(t);Simple Atomic Class Using Unsafe
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); }
}End of article.
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.
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.
