unsafe原理 java_Unsafe原理

unsafe原理 java_Unsafe原理java 生态圈 几乎每个使用 java 开发的工具 软件基础设施 高性能开发库都在底层使用了 sun misc Unsafe 这就是 SUN 未开源的 sun misc Unsafe 的类 该类功能很强大 涉及到类加载机制 其实例一般情况是获取不到的 源码中的设计是采用单例模式 不是系统加载初始化就会抛出 SecurityExce 异常 Unsafe 类官方并不对外开放 因为 Unsafe 这个类提供

java 生态圈。 几乎每个使用 java开发的工具、软件基础设施、高性能开发库都在底层使用了 sun.misc.Unsafe 。这就是SUN未开源的sun.misc.Unsafe的类,该类功能很强大,涉及到类加载机制,其实例一般情况是获取不到的,源码中的设计是采用单例模式,不是系统加载初始化就会抛出SecurityException异常。Unsafe类官方并不对外开放,因为Unsafe这个类提供了一些绕开JVM的更底层功能,基于它的实现可以提高效率。

Unsafe API的大部分方法都是native实现

分为下面几类:

Info:主要返回某些低级别的内存信息:

public native int addressSize();

public native int pageSize();

Objects:主要提供Object和它的域操纵方法

public native Object allocateInstance(Class> var1) throws InstantiationException;

public native long objectFieldOffset(Field var1);

Class:主要提供Class和它的静态域操纵方

public native long staticFieldOffset(Field var1);

public native Class> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

public native Class> defineAnonymousClass(Class> var1, byte[] var2, Object[] var3);

public native void ensureClassInitialized(Class> var1);

Arrays:数组操纵方法

public native int arrayBaseOffset(Class> var1);

public native int arrayIndexScale(Class> var1);

Synchronization:主要提供低级别同步原语

/ @deprecated */

@Deprecated

public native void monitorEnter(Object var1);

/ @deprecated */

@Deprecated

public native void monitorExit(Object var1);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public native void putOrderedInt(Object var1, long var2, int var4);

Memory:直接内存访问方法(绕过JVM堆直接操纵本地内存)

public native long allocateMemory(long var1);

public native long reallocateMemory(long var1, long var3);

public native void setMemory(Object var1, long var2, long var4, byte var6);

public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);

Unsafe类实例的获取

Unsafe类设计只提供给JVM信任的启动类加载器所使用,是一个典型的单例模式类

private Unsafe() {

}

@CallerSensitive

public static Unsafe getUnsafe() {

Class var0 = Reflection.getCallerClass();

if(!VM.isSystemDomainLoader(var0.getClassLoader())) {

throw new SecurityException(“Unsafe”);

} else {

return theUnsafe;

}

}

可以通过反射技术暴力获取Unsafe对象,下面做一个cas算法的测试

package unsafe;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class UnsafeCASTest {

public static void main(String[] args) throws Exception {

// 通过反射实例化Unsafe

Field f = Unsafe.class.getDeclaredField(“theUnsafe”);

f.setAccessible(true);

Unsafe unsafe = (Unsafe) f.get(null);

// 实例化Player

Player player = (Player) unsafe.allocateInstance(Player.class);

player.setAge(18);

player.setName(“li lei”);

for (Field field : Player.class.getDeclaredFields()) {

System.out.println(field.getName() + “:对应的内存偏移地址” + unsafe.objectFieldOffset(field));

}

System.out.println(“——————-“);

// unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)

// arg0, arg1, arg2, arg3 分别是目标对象实例,目标对象属性偏移量,当前预期值,要设的值

int ageOffset = 12;

// 修改内存偏移地址为12的值(age),返回true,说明通过内存偏移地址修改age的值成功

System.out.println(unsafe.compareAndSwapInt(player, ageOffset, 18, 20));

System.out.println(“age修改后的值:” + player.getAge());

System.out.println(“——————-“);

// 修改内存偏移地址为12的值,但是修改后不保证立马能被其他的线程看到。

unsafe.putOrderedInt(player, 12, 33);

System.out.println(“age修改后的值:” + player.getAge());

System.out.println(“——————-“);

// 修改内存偏移地址为16的值,volatile修饰,修改能立马对其他线程可见

unsafe.putObjectVolatile(player, 16, “han mei”);

System.out.println(“name修改后的值:” + unsafe.getObjectVolatile(player, 16));

}

}

class Player {

private int age;

private String name;

private Player() {

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

输出的结果是:

age:对应的内存偏移地址12

name:对应的内存偏移地址16

——————-

true

age修改后的值:20

——————-

age修改后的值:33

——————-

name修改后的值:han mei

在concurrent包是基于AQS (AbstractQueuedSynchronizer)框架的,AQS框架借助于两个类:

Unsafe(提供CAS操作)

LockSupport(提供park/unpark操作)

归根结底,LockSupport.park()和LockSupport.unpark(Thread thread)调用的是Unsafe中的native代码:

//LockSupport中

public static void park() {

UNSAFE.park(false, 0L);

}

//LockSupport中

public static void unpark(Thread thread) {

if (thread != null)

UNSAFE.unpark(thread);

}

Unsafe类中的对应方法:

//park

public native void park(boolean isAbsolute, long time);

//unpack

public native void unpark(Object var1);

park函数是将当前调用Thread阻塞,而unpark函数则是将指定线程Thread唤醒。

Unsafe.park和Unsafe.unpark的底层实现原理

在Linux系统下,是用的Posix线程库pthread中的mutex(互斥量),condition(条件变量)来实现的。

mutex和condition保护了一个_counter的变量,当park时,这个变量被设置为0,当unpark时,这个变量被设置为1。

每个Java线程都有一个Parker实例,Parker类是这样定义的:

class Parker : public os::PlatformParker {

private:

volatile int _counter ;

public:

void park(bool isAbsolute, jlong time);

void unpark();

}

class PlatformParker : public CHeapObj {

protected:

pthread_mutex_t _mutex [1] ;

pthread_cond_t _cond [1] ;

}

可以看到Parker类实际上用Posix的mutex,condition来实现的。

在Parker类里的_counter字段,就是用来记录“许可”的。

当调用park时,先尝试能否直接拿到“许可”,即_counter>0时,如果成功,则把_counter设置为0,并返回:

void Parker::park(bool isAbsolute, jlong time) {

// Ideally we’d do something useful while spinning, such

// as calling unpackTime().

// Optional fast-path check:

// Return immediately if a permit is available.

// We depend on Atomic::xchg() having full barrier semantics

// since we are doing a lock-free update to _counter.

if (Atomic::xchg(0, &_counter) > 0) return;

如果不成功,则构造一个ThreadBlockInVM,然后检查_counter是不是>0,如果是,则把_counter设置为0,unlock mutex并返回:

ThreadBlockInVM tbivm(jt);

if (_counter > 0) { // no wait needed

_counter = 0;

status = pthread_mutex_unlock(_mutex);

否则,再判断等待的时间,然后再调用pthread_cond_wait函数等待,如果等待返回,则把_counter设置为0,unlock mutex并返回:

if (time == 0) {

status = pthread_cond_wait (_cond, _mutex) ;

}

_counter = 0 ;

status = pthread_mutex_unlock(_mutex) ;

assert_status(status == 0, status, “invariant”) ;

OrderAccess::fence();

unpark

当unpark时,则简单多了,直接设置_counter为1,再unlock mutex返回。如果_counter之前的值是0,则还要调用pthread_cond_signal唤醒在park中等待的线程:

void Parker::unpark() {

int s, status ;

status = pthread_mutex_lock(_mutex);

assert (status == 0, “invariant”) ;

s = _counter;

_counter = 1;

if (s < 1) {

if (WorkAroundNPTLTimedWaitHang) {

status = pthread_cond_signal (_cond) ;

assert (status == 0, “invariant”) ;

status = pthread_mutex_unlock(_mutex);

assert (status == 0, “invariant”) ;

} else {

status = pthread_mutex_unlock(_mutex);

assert (status == 0, “invariant”) ;

status = pthread_cond_signal (_cond) ;

assert (status == 0, “invariant”) ;

}

} else {

pthread_mutex_unlock(_mutex);

assert (status == 0, “invariant”) ;

}

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212342.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午8:16
下一篇 2026年3月18日 下午8:16


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号