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