当我阅读sun.misc.Unsafe.Java
的代码时,我遇到了一个问题。
CAS是一个像旋转一样的循环吗?
起初,我认为CAS只是一种低生存的原子操作。但是,当我尝试找到函数compareAndSwapInt
的源代码时,我发现这样的cpp代码:
jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
assert(sizeof(jbyte) == 1, "assumption.");
uintptr_t dest_addr = (uintptr_t)dest;
uintptr_t offset = dest_addr % sizeof(jint);
volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
jint cur = *dest_int;
jbyte* cur_as_bytes = (jbyte*)(&cur);
jint new_val = cur;
jbyte* new_val_as_bytes = (jbyte*)(&new_val);
new_val_as_bytes[offset] = exchange_value;
while (cur_as_bytes[offset] == compare_value) {
jint res = cmpxchg(new_val, dest_int, cur);
if (res == cur) break;
cur = res;
new_val = cur;
new_val_as_bytes[offset] = exchange_value;
}
return cur_as_bytes[offset];
}
我在这个原子功能中看到“何时”和“休息”。
这是旋转方式吗?
相关代码链接:
http://hg.openjdk.java.net/jdk8u/jdk8u20/hotspot/file/190899198332/src/share/vm/prims/unsafe.cpp
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/07011844584f/src/share/classes/sun/misc/Unsafe.java
http://hg.openjdk.java.net/jdk8u/jdk8u20/hotspot/file/55fb97c4c58d/src/share/vm/runtime/atomic.cpp
答案 0 :(得分:4)
CAS
是单个操作,返回值1
或0
,意味着此操作已成功或不成功,因为您正在执行{ {1}}您希望此操作成功,因此操作会重复进行,直到它正常工作。
我认为你也混淆了compareAndSwapInt
,这基本上意味着做一些事情,而这个值是" 1" (例如);所有其他线程一直等到这个值为零(通过spin lock
),这实际上意味着某个线程完成了工作并释放了锁(这称为compareAndSwap
语义)
答案 1 :(得分:4)
CAS操作不是旋转,它是硬件级别的原子操作。在x86和SPARC处理器CAS上只有一条指令,它支持int
和long
个操作数。
确实使用单个cmpxchgl
/ {在x86上生成Atomic::cmpxchg
int
/ long
重载{3}}指示。
您正在查看的内容是Atomic::cmpxchg
单一 byte
重载,它适用于CAS指令的限制,以模拟CAS <\ n强> byte
级别。它是通过为与int
位于同一地址的byte
执行CAS,然后只检查一个byte
并重复CAS,如果因为更改而导致CAS失败其他3个字节。比较和交换仍然是原子的,有时需要重新尝试,因为它覆盖了比必要更多的字节。
答案 2 :(得分:0)
__atomic_compare_exchange
除非两种情况适用,否则我的建议不要担心所有这些都有效:
单元测试可以帮助您识别前一种情况。基准测试可以帮助您识别后一种情况。但应该指出的是,如果Java提供给您的CAS很慢,那么您可能无法自己编写更快的CAS。因此,在这种情况下,最好的办法是更改数据结构或数据流,以进一步减少所需的线程同步量。