首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Java并发编程:AQS的原子性如何保证

当我们研究AQS框架时(对于AQS不太熟知可以先阅读《什么是JDK内置并发框架AQS》,会发现AbstractQueuedSynchronizer这个类很多地方都使用了CAS操作。在并发实现中CAS操作必须具备原子性,而且是硬件级别的原子性。我们知道Java被隔离在硬件之上,硬件级别的操作明显力不从心。这时为了能够执行操作系统层面的操作,就必须要通过用C++编写的native本地方法来扩展实现。一般可以通过JNI方式实现Java代码调用C++代码

Unsafe调用

JDK提供了一个类来满足CAS的硬件级别原子性要求,即sun.misc.Unsafe类,从名字上大概知道它用于执行低级别、不安全的操作,AQS就是使用此类来完成硬件级别的原子操作。也就是说通过该类就能实现对处理器的原子操作,Unsafe通过JNI调用本地C++代码,C++代码调用了硬件指令集,这些硬件指令集都属于CPU。

Unsafe的魔法

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

image.png

Unsafe的用途

一般情况下,我们都没有特殊的需求去使用它。而且它的使用必须限定在受信任代码,这些代码一般由JVM指定。例如直接Unsafe unsafe = Unsafe.getUnsafe();获取一个Unsafe实例是不会成功的,因为这个类的安全性很重要,设计者对其进行了安全检查。如下代码所示,它会检测调用它的类是否由启动类加载器Bootstrap ClassLoader(它的类加载器为null)加载,由此来保证此类只能由JVM指定的类使用。

Unsafe实现CAS

因为存在安全性问题,所以如果我们要用Unsafe类则需要另辟蹊径。可行的方法就是通过反射来绕过上述的安全检查,我们可以通过以下的getUnsafeInstance方法来获取Unsafe实例。这段代码演示了如何获取Java对象的相对地址偏移量以及使用Unsafe来完成CAS操作,最终输出的是flag字段的内存偏移量及CAS操作后的值。最终的输出为“unsafeTest对象的flag字段的地址偏移量为:12”和“CAS操作后的flag值为:101”。另外如果使用开发工具如Eclipse,可能会编译通不过,只要把编译错误提示关掉即可。

总结

这里主要讲解了Unsafe类如何让Java层能实现硬件级别的原子操作,同时也了解了Unsafe类拥有很多法魔技能。通常我们使用Java时不需要在内存中处理Java对象及内存地址位置,但有的时候我们被迫必须要操作Java对象相关的地址,于是我们只能使用Unsafe类。使用该类则意味着破坏了Java平台隔离的效果了,我们都知道一旦用了本地方法则可能会引来跨平台问题。

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/05516b2a11d576b74e49df634
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券