一、内容:
主要简单说下AtomicInteger的getAndIncrement的实现方式
二、跟随源码到达最深的位置:
java入口:
unsafe-java:
unsafe-native-method(可以看到是native方法,说明是调用本地的c++相关代码方法):
通过下载openjdk1.7,在hotspot/src/share/vm/prims/unsafe.cpp可以找到下面的接口:
最终可以到达hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp:
这段内联汇编代码便是最终的核心代码了
1.cas(比较赋值)是通过x86指令cmpxchgl实现的。
2.该内联代码等价伪汇编代码(因为实际compare_value、exchange_value和desc是不能这么直接写在汇编里的,这里只是个大体意思):
mov compare_value, %eax
mov exchange_value, %edx
mov dest, %rcx
mov is_mutiple_processor, %esi
cmp $0, %esi; je 1f; lock; 1: cmpxchgl %edx,(%rcx)
1.
寄存器eax存放着compare_value(旧值-即dest内存中所指向位置的值)的值,
寄存器edx存放着exchange_value(要修改的值)的值,
寄存器rcx存放的是dest(要修改内存中的地址值)的值,
寄存器esi存放是当前系统运行的是否是多核系统
2.cmp $0, %esi; je 1f;
判断当前是否是单核系统,是的话跳到1:处(即会跳过lock指令,不执行)
如果为多核系统,则会继续往下执行,则会执行lock指令
3.lock指令
lock执行跟随的后面的相关指令会变为原子操作,相关地址描述:http://www.felixcloutier.com/x86/LOCK.html
4.cmpxchgl %edx, (%rcx)
这里会读取(%rcx)中所指向内存的值temp,然后判断该值temp和寄存器eax所存放的值(compare_value)是否相等,
如果相等,则会将寄存器中edx的值存入到(%rcx)所指向内存的位置上,额外zf会设置为1
如果不相等,则会将temp值存入到(%rcx)所指向内存的位置上,额外zf会设置为0
所以在多核模式下,一个线程比较的值temp和后面写入时的temp的值可能已经发生改变了,因此需要加lock前缀指令,来保证多核情况下该cmpxchgl指令为原子操作。
lock前缀指令并不是所有指令适用,相关地址描述:http://www.felixcloutier.com/x86/CMPXCHG.html