欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java原子类中CAS的底层实现

程序员文章站 2022-07-02 13:46:12
Java原子类中CAS的底层实现 从Java到c++到汇编, 深入讲解cas的底层原理. 介绍原理前, 先来一个Demo 以AtomicBoolean类为例.先来一个调用cas的demo. 主线程在for语句里cas忙循环, 直到cas操作成功返回true为止. 而新开的一个县城new Thread ......

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的底层实现

其中 __asm__ volatile 指示了编译器不要改动优化后面的汇编语句, 如果进行了优化(优化是为了减少访问内存, 直接通过缓存, 加快取读速度), 那么就在这段函数的周期内, 某几个变量就相当于常亮了, 其值可能会与内存中真实的值有差异.

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