Java原子类中CAS的底层实现

编程语言与高级语言虚拟机杂谈仮 2018-05-27

Java原子类中CAS的底层实现

从Java到c++到汇编, 深入讲解cas的底层原理.

介绍原理前, 先来一个Demo

以AtomicBoolean类为例.先来一个调用cas的demo.

主线程在for语句里cas忙循环, 直到cas操作成功返回true为止.

而新开的一个县城new Thread 会在4秒后,将flag设置为true, 为了让主线程能够设置成功.(因为cas的预期值是true, 而flag被初始化为了false)

现象就是主线程一直在跑for循环. 4秒后, 主线程将会设置成功, 然后输出时间差, 然后终止for循环.

public class TestAtomicBoolean {
    public static void main(String[] args) {
        AtomicBoolean flag = new AtomicBoolean(false);

        long start = System.currentTimeMillis();

        new Thread(()->{
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag.set(true);
        }).start();

        for(;;){
            if(flag.compareAndSet(true,false)){
                System.out.println(System.currentTimeMillis() - start);
                System.out.println("inner loop OK!");
                break;
            }
        }
    }
}

这里只是举了一个例子, 也许这个例子也不太恰当, 本文只是列出了这个api的调用方法而已, 重点在于介绍compareAndSet()方法的底层原理.

Java级源码AtomicBoolean.java

发现AtomicBoolean的compareAndSet()调用的是unsafe里的compareAndSwapInt()方法.

Java原子类中CAS的底层实现

Java级源码Unsafe.java

有的同学可能好奇, 其中的unsafe是怎么来的.

在AtomicBoolean类中的静态成员变量:

Java原子类中CAS的底层实现

如果还要细究Unsafe.getUnsafe()是怎么实现的话....那么我再贴一份Unsafe类里的getUnsafe的代码:

首先, 在Unsafe类里, 自己就有了一个自己的实例.(单例)

Java原子类中CAS的底层实现

然后Unsafe类里的getUnsafe()方法会进行检查, 最终会return这个单例 theUnsafe.

Java原子类中CAS的底层实现

刚刚跑去取介绍了getUnsafe()方法...接下来继续讲解cas...

刚才说到了AtomicBoolean类里的compareAndSet()方法内部其实调用了Unsafe类里的compareAndSwapInt()方法.

Unsafe类里的compareAndSwapInt源码如下:

(OpenJDK8的源码里路径: openjdk/jdk/src/share/classes/sun/misc/Unsafe.java)

Java原子类中CAS的底层实现

发现这里是一段native方法.说明继续看源码的话, 从这里就开始脱离Java语言了....

c++级源码Unsafe.cpp

本源码在OpenJDK8里的路径为: openjdk/hotspot/src/share/vm/prims/unsafe.cpp

Java原子类中CAS的底层实现

(这里临时跑题一下: 如果说要细究 UNSAFE_ENTRY 是什么的话...UNSAFE_ENTRY 就是JVM_ENTRY, 而JVM_ENTRY 在interfaceSupport.hpp里面定义了, jni相关.如果想看的话, 源码路径在OpenJDK8中的路径是这个:

openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp)

回到本文的主题cas....上面截图的这段代码, 最后一句是return, 发现其中的使用到的是Atomic下的cmpxchg()方法.

c++级源码atomic.cpp

本段源码对应OpenJDK8的路径是这个:openjdk/hotspot/src/share/vm/runtime/atomic.cpp

Java原子类中CAS的底层实现

其中的cmpxchg为核心内容. 但是这句代码根据操作系统和处理器的不同, 使用不同的底层代码.

Java原子类中CAS的底层实现

而atomic.inline.hpp里声明如下:

可见 ...不同不同操作系统, 不同的处理器, 都要走不同的cmpxchg()方法的实现.

Java原子类中CAS的底层实现

咱们接下来以其中的linux操作系统 x86处理器为例 , atomic_linux_x86.inline.hpp

汇编级源码atomic_linux_x86.inline.hpp

OpenJDK中路径如下: openjdk/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp

看到了__asm__, 说明c++要开始内联汇编了,说明继续看代码的话, 将会是汇编语言.

这是一段内联汇编:

Java原子类中CAS的底层实现

未完待续....困了睡.....

相关推荐