我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。
扫描二维码或搜索下图红色VX号,加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。
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;
}
}
}
}
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级源码Unsafe.java
有的同学可能好奇, 其中的unsafe是怎么来的.
在AtomicBoolean类中的静态成员变量:
如果还要细究Unsafe.getUnsafe()是怎么实现的话....那么我再贴一份Unsafe类里的getUnsafe的代码:
首先, 在Unsafe类里, 自己就有了一个自己的实例.(而且是单例的)
然后Unsafe类里的getUnsafe()方法会进行检查, 最终会return这个单例 theUnsafe.
刚刚跑去取介绍了getUnsafe()方法...接下来继续讲解cas...
刚才说到了AtomicBoolean类里的compareAndSet()方法内部其实调用了Unsafe类里的compareAndSwapInt()方法.
Unsafe类里的compareAndSwapInt源码如下:
(OpenJDK8的源码里路径: openjdk/jdk/src/share/classes/sun/misc/Unsafe.java)
发现这里是一段native方法.说明继续看源码的话, 从这里就开始脱离Java语言了....
c++级源码Unsafe.cpp
本源码在OpenJDK8里的路径为: openjdk/hotspot/src/share/vm/prims/unsafe.cpp
(这里临时跑题一下: 如果说要细究 UNSAFE_ENTRY 是什么的话...UNSAFE_ENTRY 就是 JVM_ENTRY, 而 JVM_ENTRY 在interf