java unsafe类_Java unsafe

大家好,我是知秋君,一个会写博客吟诗的知秋码农。今天说一说java unsafe类_Java unsafe,希望能够帮助大家进步!!! java 生态圈。 几乎每个使用 java开发的工具、软件基础设施、高性能开发库都在底层使用了 sun.misc.Unsafe 。这就是SUN未开源的sun.misc.Unsafe的类,该类功能很强大,涉及到类加载机制,其实例一般情况是获取不到的

大家好,我是知秋君,一个会写博客吟诗的知秋码农。今天说一说java unsafe类_Java 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") ;

}

}

知秋君
上一篇 2024-07-03 15:31
下一篇 2024-07-03 15:31

相关推荐