volatile、CAS、锁、Unsafe与VarHandle

1.volatile、CAS、锁

注意CAS在高并发竞争激烈时会不断重试,性能会恶化。所以ConcurrentHashMap等会使用分散承担机制来减少竞争,从baseCount扩展到counterCells数组。

2.Unsafe

Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。

Unsafe是用于在实质上扩展Java语言表达能力、便于在更高层(Java层)代码里实现原本要在更低层(C层)实现的核心库功能用的。这些功能包括裸内存的申请/释放/访问,低层硬件的atomic/volatile支持,创建未初始化对象等。它原本的设计就只应该被标准库使用。

从JDK9开始,Java的新模块化设计将使得非标准库的模块都无法访问到sun.misc.Unsafe。所以就算为了“向未来兼容”也请不要直接使用sun.misc.Unsafe。事实上标准库里也只有jdk.base模块能访问到sun.misc.Unsafe,因为它被设计成了非exported类。

使用Unsafe几乎可以操作一切:

  • 1)实例化一个类;
  • 2)修改私有字段的值;
  • 3)抛出checked异常;
  • 4)使用堆外内存;
  • 5)CAS操作;
    JUC下面大量使用了CAS操作,它们的底层是调用的Unsafe的CompareAndSwapXXX()方法。这种方式广泛运用于无锁算法,与java中标准的悲观锁机制相比,它可以利用CAS处理器指令提供极大的加速。
  • 6)阻塞/唤醒线程;
    JVM在上下文切换的时候使用了Unsafe中的两个方法park()和unpark()。
    当一个线程正在等待某个操作时,JVM调用Unsafe的park()方法来阻塞此线程。
    当阻塞中的线程需要再次运行时,JVM调用Unsafe的unpark()方法来唤醒此线程。

3.VarHandle

变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。变量句柄的含义类似于已有的方法句柄。变量句柄由 Java 类 java.lang.invoke.VarHandle 来表示。可以使用类 java.lang.invoke.MethodHandles.Lookup 中的静态工厂方法来创建 VarHandle 对 象。通过变量句柄,可以在变量上进行各种操作。这些操作称为访问模式。不同的访问模式尤其在内存排序上的不同语义。目前一共有 31 种 访问模式,而每种访问模式都 在 VarHandle 中 有对应的方法。这些方法可以对变量进行读取、写入、原子更新、数值原子更新和比特位原子操作等。VarHandle 还可以用来访问数组中的单个元素,以及把 byte[]数组 和 ByteBuffer 当成是不同原始类型的数组来访问。

VarHandle提供的内存屏障,这些屏障都是通过底层Unsafe实现的。

    @ForceInline
    public static void fullFence() {
        UNSAFE.fullFence();
    }

    @ForceInline
    public static void acquireFence() {
        UNSAFE.loadFence();
    }

    @ForceInline
    public static void releaseFence() {
        UNSAFE.storeFence();
    }

    @ForceInline
    public static void loadLoadFence() {
        UNSAFE.loadLoadFence();
    }

    @ForceInline
    public static void storeStoreFence() {
        UNSAFE.storeStoreFence();
    }

VarHandle 的出现替代了java.util.concurrent.atomic和sun.misc.Unsafe的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的API。

Oracle的Java开发团队一直在努力提高Java性能,尽可能消除大家因为性能不足而要转向Unsafe的状况。VarHandle、Arrays 2.0都是这方面的努力。

并且在JEP 193中明确指出:那些在包 java.util.concurrent 里的类(包括 JDK 中其他一下地方)会从 sun.misc.Unsafe 迁移到 VarHandle。在JDK10中,JUC下面的atomic locks已迁移到了VarHandle。

参考

  • Java魔法类:Unsafe应用解析
  • Java 9 新特性概述
  • JEP 193: Variable Handles
  • 翻译 - JEP 193:Variable Handles

你可能感兴趣的:(volatile、CAS、锁、Unsafe与VarHandle)