首页 > 其他 > 详细

并发学习第六篇——Unsafe类和CAS

时间:2021-03-06 23:32:57      阅读:30      评论:0      收藏:0      [点我收藏+]

之前看JUC的源码,一直有发现一个怪异的类:Unsafe,怪,是因为名字有点怪......它在sun.misc包下,

不属于Java标准,但是很多java的高性能的类都基于Unsafe,而且它竟然可以直接操作内存,让java直

接操作内存是很危险的,这个类就明着告诉我们,不安全,不要直接用我

先看一个最常见到的方法:getUnsafe()

private Unsafe() {} 

private static final Unsafe theUnsafe = new Unsafe();

@CallerSensitive  ------这个注解查了下是用来控制权限的,跟踪到最初的调用者,望文生义:调用者敏感的
public static Unsafe getUnsafe() {
     Class<?> caller = Reflection.getCallerClass();
//仅在BootstrapClassLoader加载时是合法的
if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; }

很容易看出来是个单列模式,上面的注解,用来控制权限,可以跟踪到最初的调用者,可以望文生义的理解:

调用者敏感;普通调用者调用直接抛异常,必须是systemDomainLoader这样的classLoader(BootstrapClassLoader)

Unsafe类提供的API的脑图:

技术分享图片

CAS操作

/** 
* @param o 包含要修改field的对象
* @param offset 对象中某field的偏移量
* @param expected 期望值(预期的原值)
* @param update 更新值
* @return true | false
*/

public
native boolean compareAndSwapInt(Object obj, long offset, int expect, int update); public native boolean compareAndSwapLong(Object obj, long offset, long expect, long update); public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);

Unsafe提供的CAS操作有这三个,都是compareAndSwapXXX的形式,执行的是一条CPU的原子指令(cmpxchg)

CAS操作有3个操作数,内存值M,预期值E,新值U,如果M==E,则将内存值修改为U,否则啥都不做

这个对比下mysql中的MVCC机制很好理解,MVCC存的是个隐藏的版本号值,做记录变更的操作时会拿

先前已经获取到的版本号跟当前记录最新的版本号做比较(就像比较M和E),然后决定操作是成功还是失败

典型应用:java.util.concurrent.atomic相关类、Java AQS、CurrentHashMap

内存操作

包含堆外内存的分配、拷贝、释放、给定地址值操作等方法

在Java中创建的对象都处于堆内内存(heap)中,堆内内存是由JVM所管控的Java进程内存,遵循JVM的内存

管理机制,JVM会采用垃圾回收机制统一管理堆内存。

堆外内存存在于JVM管控之外的内存区域,Java中对堆外内存的操作,依赖于Unsafe提供的和memory相关的

native方法,如分配内存allocateMemory,扩充内存reallocateMemory,释放内存freeMemory

线程调度

包括线程的挂起,恢复,锁机制方法

//取消阻塞线程 
public native void unpark(Object thread); 
//阻塞线程 
public native void park(boolean isAbsolute, long time); 
//获得对象锁(可重入锁) 
@Deprecated 
public native void monitorEnter(Object o); //释放对象锁 @Deprecated
public native void monitorExit(Object o); //尝试获取对象锁 @Deprecated
public native boolean tryMonitorEnter(Object o);

锁机制相关的native方法已过时,不关注

park:将一个线程挂起,调用park方法后,线程将一直阻塞直到超时或者中断等条件出现;

unpark:终止一个挂起的线程,使其恢复正常

典型应用:

Java锁和同步器框架的核心类AbstractQueuedSynchronizer,通过调用LockSupport.park()LockSupport.unpark()

实现线程的阻塞和唤醒,LockSupport的park、unpark方法实际是调用Unsafe的park、unpark方式来实现

LockSupport先点名,下一篇上

内存屏障

有点熟悉,volatile也用到了内存屏障,用来禁止代码重排序,Unsafe的这几个方法也是为了禁止重排,理解上是一样的

//内存屏障,禁止load操作重排序。屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前
public native void loadFence();
//内存屏障,禁止store操作重排序。屏障前的store操作不能被重排序到屏障后,屏障后的store操作不能被重排序到屏障前
public native void storeFence();
//内存屏障,禁止load、store操作重排序
public native void fullFence();

典型应用

java8中读写锁的改进版本:StampedLock

StampedLock.validate方法源码:

技术分享图片

 

 StampedLock的典型用法是

1、获取乐观读锁

2、copy变量到工作内存

3、锁状态检测

其中第2和3步要保证不会发生重排序,因为按照执行逻辑,2必须在3之前发生,3处使用loadFence()加上内存屏障,保证顺序

StampedLock类,后面介绍

其他功能,碰到的位置比较少,不做介绍

总结Unsafe类

单例模式的体现;

提供了很多native的不安全操作的方法;

提供了三个CAS原子操作的API方法;

提供了JUC下实现"锁"的基本类(Atomic,AQS,LockSupport)所需的线程调度和CAS方法

 

并发学习第六篇——Unsafe类和CAS

原文:https://www.cnblogs.com/yb38156/p/14434497.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!