并发编程 — 5. Unsafe类

     Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。可以通过类似 C语言里面的 memcpy 和 memset等函数直接操作对应内存地址的数据。

      Unsafe是单例模式,通过调用getUnsafe方法来获取Unsafe实例。但是在方法中通过判断ClassLoader是不是启动类BootStrap ClassLoader来决定是否返回,从而限制了用户去调用Unsafe实例的获取。原因应该就是它能直接操作内存,这交给用户肯定是不安全的。这也是java抛弃指针的原因。

public static Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
        throw new SecurityException("Unsafe");
    } else {
        return theUnsafe;
    }
}

     但是可以通过反射的方式来创建一个实例来:

Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);

   通过这个Unsafe实例,可以进行内存管理、线程挂起和恢复、多线程同步、内存屏障等。具体方法列表详见https://www.cnblogs.com/throwable/p/9139947.html

内存管理

假设有个类A,它拥有一个属性value。利用Unsafe,可以通过修改内存的方式操纵对象属性给value赋值。

class A{
    private int value;
    public A() {}
    public int getValue() { return value; }
}

通过下面这个方法可以计算value属性值的内存偏移量:

public native long objectFieldOffset(Field f);

按照以下方式即可修改属性值:

A a = new A();

Field field =  Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe)field.get(null);

Field value = A.class.getDeclaredField("value");
long Offset = unsafe.objectFieldOffset(value);

unsafe.setMemory(a,Offset,1, (byte)0x64);
System.out.println(a.getValue());

线程挂起与恢复

在多线程开发时,为了防止并发问题,可以通过park和unpark方法来进行线程的挂起和恢复。

public native void park(boolean isAbsolute, long time);阻塞当前线程直到出现以下三种种情况之一:一个用于unpark方法已经出现过(在此park方法调用之前已经调用过)、线程被中断或者time时间到期(也就是阻塞超时)。
public native void unpark(Object thread);

释放被park创建的在一个线程上的阻塞。

多线程同步

AQS(阻塞同步机制)和CAS(非阻塞同步机制)的底层就是由Unsafe实现的。

public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
针对Object对象进行CAS操作。即是对应Java变量引用o,原子性地更新o中偏移地址为offset的属性的值为x,当且仅的偏移地址为offset的属性的当前值为expected才会更新成功返回true,否则返回false。

o:目标Java变量引用。
offset:目标Java变量中的目标属性的偏移地址。
expected:目标Java变量中的目标属性的期望的当前值。
x:目标Java变量中的目标属性的目标更新值。

内存屏障

public native void loadFence();
在该方法之前的所有读操作,一定在load屏障之前执行完成。

public native void storeFence();
在该方法之前的所有写操作,一定在store屏障之前执行完成

public native void fullFence();
在该方法之前的所有读写操作,一定在full屏障之前执行完成,这个内存屏障相当于上面两个(load屏障和store屏障)的合体功能。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值