JDK并发AQS系列(二)

原子性

在研究JDK中AQS时,会发现这个类不少地方都使用了CAS操做,在并发实现中CAS操做必须具有原子性,并且是硬件级别的原子性,java被隔离在硬件之上,明显力不从心,这时为了能直接操做操做系统层面,确定要经过用C++编写的native本地方法来扩展实现。JDK提供了一个类来知足CAS的要求,sun.misc.Unsafe,从名字上能够大概知道它用于执行低级别、不安全的操做,AQS就是使用此类完成硬件级别的原子操做。java

Unsafe类

Unsafe是一个很强大的类,它能够分配内存、释放内存、能够定位对象某字段的位置、能够修改对象的字段值、可使线程挂起、使线程恢复、可进行硬件级别原子的CAS操做等等。mysql

但平时咱们没有这么特殊的需求去使用它,并且必须在受信任代码(通常由JVM指定)中调用此类,例如直接Unsafe unsafe = Unsafe.getUnsafe();获取一个Unsafe实例是不会成功的,由于这个类的安全性很重要,设计者对其进行了以下判断,它会检测调用它的类是否由启动类加载器Bootstrap ClassLoader(它的类加载器为null)加载,由此保证此类只能由JVM指定的类使用。判断逻辑以下,sql

public static Unsafe getUnsafe() {

   Class cc = sun.reflect.Reflection.getCallerClass(2);

   if (cc.getClassLoader() != null)

       throw new SecurityException("Unsafe");

   return theUnsafe;

}
复制代码

获取Unsafe

固然能够经过反射绕过上面的限制,用下面的getUnsafeInstance方法能够获取Unsafe实例,这段代码演示了如何获取java对象的相对地址偏移量及使用Unsafe完成CAS操做,最终输出的是flag字段的内存偏移量及CAS操做后的值。分别为8和101。另外若是使用开发工具如Eclipse,可能会编译通不过,只要把编译错误提示关掉便可。安全

public class UnsafeTest {

privateint flag = 100;
privatestatic long offset;
privatestatic Unsafe unsafe = null;

static{
     try{
          unsafe= getUnsafeInstance();
          offset= unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("flag"));
     }catch (Exception e) {
          e.printStackTrace();
     }
}

publicstatic void main(String[] args) throws Exception {

     intexpect = 100;
     intupdate = 101;

     UnsafeTestunsafeTest = new UnsafeTest();
     System.out.println("unsafeTest对象的flag字段的地址偏移量为:"+offset);
     unsafeTest.doSwap(offset,expect, update);
     System.out.println("CAS操做后的flag值为:" +unsafeTest.getFlag());

}

privateboolean doSwap(long offset, int expect, int update) {
     returnunsafe.compareAndSwapInt(this, offset, expect, update);
}

publicint getFlag() {
     returnflag;
}

privatestatic Unsafe getUnsafeInstance() throws SecurityException,NoSuchFieldException,IllegalArgumentException,IllegalAccessException{
     FieldtheUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
     theUnsafeInstance.setAccessible(true);
     return(Unsafe) theUnsafeInstance.get(Unsafe.class);
}

}
复制代码

Unsafe类让咱们明白了java是如何实现对操做系统操做的,通常咱们使用java是不须要在内存中处理java对象及内存地址位置的,但有的时候咱们确实须要知道java对象相关的地址,因而咱们使用Unsafe类,尽管java对其提供了足够的安全管理。bash

总结

Java语言的设计者们极力隐藏涉及底层操做系统的相关操做,但这里咱们为了探索AQS的实现,不得不剖析了Unsafe类,由于AQS里面便是使用Unsafe获取对象字段的地址偏移量、相关原子操做来实现CAS操做的。网络

-------------推荐阅读------------并发

个人开源项目汇总(机器&深度学习、NLP、网络IO、AIML、mysql协议、chatbot)机器学习

为何写《Tomcat内核设计剖析》工具

个人2017文章汇总——机器学习篇学习

个人2017文章汇总——Java及中间件

个人2017文章汇总——深度学习篇

个人2017文章汇总——JDK源码篇

个人2017文章汇总——天然语言处理篇

个人2017文章汇总——Java并发篇


跟我交流,向我提问:

欢迎关注:

相关文章
相关标签/搜索