从JDK源码角度看java并发的原子性如何保证

简介:         JDK源码中,在研究AQS框架时,会发现很多地方都使用了CAS操作,在并发实现中CAS操作必须具备原子性,而且是硬件级别的原子性,java被隔离在硬件之上,明显力不从心,这时为了能直接操作操作系统层面,肯定要通过用C++编写的native本地方法来扩展实现。

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

        Unsafe是一个很强大的类,它可以分配内存、释放内存、可以定位对象某字段的位置、可以修改对象的字段值、可以使线程挂起、使线程恢复、可进行硬件级别原子的CAS操作等等,但平时我们没有这么特殊的需求去使用它,而且必须在受信任代码(一般由JVM指定)中调用此类,例如直接Unsafe unsafe = Unsafe.getUnsafe();获取一个Unsafe实例是不会成功的,因为这个类的安全性很重要,设计者对其进行了如下判断,它会检测调用它的类是否由启动类加载器Bootstrap ClassLoader(它的类加载器为null)加载,由此保证此类只能由JVM指定的类使用。

public static Unsafe getUnsafe() {
   Class cc = sun.reflect.Reflection.getCallerClass(2);
   if (cc.getClassLoader() != null)
       throw new SecurityException("Unsafe");
   return theUnsafe;
}

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

public class UnsafeTest {
private int flag = 100;
private static long offset;
private static Unsafe unsafe = null;
static{
     try{
          unsafe= getUnsafeInstance();
          offset= unsafe.objectFieldOffset(UnsafeTest.class
                   .getDeclaredField("flag"));
     }catch (Exception e) {
          e.printStackTrace();
     }
}
 
public static void main(String[] args) throws Exception {
     int expect = 100;
     int update = 101;
     UnsafeTest unsafeTest = 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;
}
 
private static Unsafe getUnsafeInstance() throws SecurityException,
          NoSuchFieldException,IllegalArgumentException,
          IllegalAccessException{
     Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
     theUnsafeInstance.setAccessible(true);
     return (Unsafe)theUnsafeInstance.get(Unsafe.class);
}
}

        Unsafe类让我们明白了java是如何实现对操作系统操作的,一般我们使用java是不需要在内存中处理java对象及内存地址位置的,但有的时候我们确实需要知道java对象相关的地址,于是我们使用Unsafe类,尽管java对其提供了足够的安全管理。

        Java语言的设计者们极力隐藏涉及底层操作系统的相关操作,但此节我们本着对AQS框架实现的目的,不得不剖析了Unsafe类,因为AQS里面即是使用Unsafe获取对象字段的地址偏移量、相关原子操作来实现CAS操作的。


====广告时间,可直接跳过====

鄙人的新书《Tomcat内核设计剖析》已经在京东预售了,有需要的朋友可以到https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

=========================



欢迎关注:



目录
相关文章
|
4天前
|
运维 Java
Java版HIS系统 云HIS系统 云HIS源码 结构简洁、代码规范易阅读
云HIS系统分为两个大的系统,一个是基层卫生健康云综合管理系统,另一个是基层卫生健康云业务系统。基层卫生健康云综合管理系统由运营商、开发商和监管机构使用,用来进行运营管理、运维管理和综合监管。基层卫生健康云业务系统由基层医院使用,用来支撑医院各类业务运转。
23 5
|
1天前
|
Java Linux Shell
【Linux】bash: /home/stefan/jdk1.7.0_55/bin/java: /lib/ld-linux.so.2: bad ELF interpreter
【Linux】bash: /home/stefan/jdk1.7.0_55/bin/java: /lib/ld-linux.so.2: bad ELF interpreter
5 0
|
5天前
|
JavaScript Java 测试技术
基于Java的电影评论系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的电影评论系统的设计与实现(源码+lw+部署文档+讲解等)
20 0
|
5天前
|
JavaScript Java 测试技术
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的在线日语培训平台的设计与实现(源码+lw+部署文档+讲解等)
23 0
|
5天前
|
JavaScript Java 测试技术
基于Java的同城蔬菜配送管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的同城蔬菜配送管理系统的设计与实现(源码+lw+部署文档+讲解等)
10 0
|
5天前
|
JavaScript Java 测试技术
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
21 0
基于Java的心理预约咨询管理系统的设计与实现(源码+lw+部署文档+讲解等)
|
5天前
|
JavaScript Java 测试技术
基于Java的税务门户网站的设计与实现(源码+lw+部署文档+讲解等)
基于Java的税务门户网站的设计与实现(源码+lw+部署文档+讲解等)
3 0
|
5天前
|
JavaScript Java 测试技术
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
20 0
基于Java的高校毕业生就业管理系统的设计与实现(源码+lw+部署文档+讲解等)
|
5天前
|
JavaScript Java 测试技术
基于Java的家纺用品销售管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的家纺用品销售管理系统的设计与实现(源码+lw+部署文档+讲解等)
15 0
|
5天前
|
JavaScript Java 测试技术
基于Java的教务管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的教务管理系统的设计与实现(源码+lw+部署文档+讲解等)
19 0