Fundamentals 9 min read

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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Unlocking Java’s Unsafe: Access Low‑Level Memory and Concurrency Safely

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

unsafeatomic operationslow-level memory
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.