推荐链接:
总结——》【Java】
总结——》【Mysql】
总结——》【Redis】
总结——》【Kafka】
总结——》【Spring】
总结——》【SpringBoot】
总结——》【MyBatis、MyBatis-Plus】
Java——》AtomicInteger源码分析
- 一、测试用例
- 二、反编译
- 三、源码
- 1、JDK源码
- 2、调用本地方法的源码和汇编代码
- (1)本地方法的源码
- (2)本地的汇编源码
- 1)linux_x86底层实现
- 2)windows_x86底层实现
一、测试用例
import java.util.concurrent.atomic.AtomicInteger;
public class CasTest {
private static volatile int m = 0;
private static final AtomicInteger x = new AtomicInteger(0);
public static void increase1() {
m++;
}
public static void increase2() {
x.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
Thread[] t1 = new Thread[20];
for (int i = 0; i < 20; i++) {
t1[i] = new Thread(CasTest::increase1);
t1[i].start();
t1[i].join(); // join 起了作用
}
Thread[] t2 = new Thread[20];
for (int i = 0; i < 20; i++) {
t2[i] = new Thread(CasTest::increase2);
t2[i].start();
t2[i].join(); // join 起了作用
}
System.out.println("int = " + m);
System.out.println("AtomicInteger = " + x.get());
}
}
二、反编译
E:\>javap -v "E:\IdeaProjects_mine\demo\target\test-classes\com\example\demo\CasTest.class"
三、源码
Unsafe 是 CAS 的核心类,Java 无法直接访问底层操作系统,而是通过本地(native)方法来访问。不过尽管如此,JVM 还是开了一个后门:Unsafe 类,它提供了硬件级别的原子操作。
incrementAndGet() -> unsafe 类 -> getAndAddInt 方法 -> compareAndSwapInt 本地方法 -> unsafe.cpp -> atomic_windows_x86.inline.hpp 汇编 -> 最终调用 cmpxchg 指令实现一条语句自增
1、JDK源码
2、调用本地方法的源码和汇编代码
(1)本地方法的源码
路径:\hotspot\src\share\vm\prims\unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj); //查找要指定的对象
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); //获取要操作的是对象的字段的内存地址
return (jint)(Atomic::cmpxchg(x, addr, e)) == e; //执行Atomic类中的cmpxchg
UNSAFE_END
(2)本地的汇编源码
JVM源码对不同操作系统和不同CPU有不同的实现,但都放在\hotspot\src\os_cpu 目录下。
操作系统 | 文件路径 |
---|---|
linux_64x | \hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp |
windows_64x | \hotspot\src\os_cpu\windows_x86\vm\atomic_windows_x86.inline.hpp |
1)linux_x86底层实现
linux_x86底层实现\hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
int mp = os::is_MP(); // 内联函数,用来判断当前系统是否为多处理器
__asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
: "cc", "memory");
return exchange_value;
}
2)windows_x86底层实现
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
// alternative for InterlockedCompareExchange
int mp = os::is_MP(); // 内联函数,用来判断当前系统是否为多处理器(如果当前系统是多处理器返回1,否则返回0)
__asm {
mov edx, dest
mov ecx, exchange_value
mov eax, compare_value
LOCK_IF_MP(mp) // 如果当前系统是多处理器(即mp值为1),则为cmpxchg指令添加lock前缀,否则不加lock前缀
cmpxchg dword ptr [edx], ecx // cmpxchg是汇编指令,作用是比较并交换操作数
}
}
Q:为什么要判断当前系统是否为多处理器?
A:这是一种优化手段,认为单处理器的环境没有必要添加lock前缀,只有在多核情况下才会添加lock前缀,因为lock会导致性能下降。