摘要:中对应拥有三个方法和,他们都被标记为它的核心实现为实现核心如下位平台运行的程序在位上会占用更大的长度,可以使用压缩指针,达到节约内存的目的。只能是一个变量问题。自身提供了来解决这个问题,原理是添加一个额外的版本来做判断源码来自
unsafe中对应拥有三个方法 compareAndSwapObject ,compareAndSwapInt和compareAndSwapLong ,他们都被标记为native
compareAndSwapObject它的核心实现为
oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
实现核心如下
inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value, volatile HeapWord *dest, oop compare_value) { if (UseCompressedOops) { narrowOop val = encode_heap_oop(exchange_value); narrowOop cmp = encode_heap_oop(compare_value); narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp); return decode_heap_oop(old); } else { return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value); } }
UseCompressedOops: 32位平台运行的程序在64位上会占用更大的长度,可以使用 -XX:+UserCompressedOops压缩指针,达到节约内存的目的。compareAndSwapInt
核心代码如下
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;compareAndSwapLong
核心代码如下
if (VM_Version::supports_cx8()) return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; else { jboolean success = false; ObjectLocker ol(p, THREAD); if (*addr == e) { *addr = x; success = true; } return success; }
supports_cx8:判断硬件是不是支持8-byte compare-exchange , x86架构中通过cpuid指令来获取是否试支持,CMPXCHG8指令 ;SPARC架构也是看 (_features & v9_instructions_m)指令的支持情况
Atomic::cmpxchg无论是那个调用,最终都归结到了Atomic上,Atomic.hpp中函数声明如下
//比较当前的值和目的地址的值,如果比较成功,就把目的地址的值更改为exchange_value,并返回原来存的值 static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value); static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value); static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value); static unsigned int cmpxchg(unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value); static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value); static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value);
从Atomic.cpp可以看到在不同的操作系统中有不同的实现
在 windows_x86中,一种实现如下
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { int mp = os::is_MP(); //查看是否是多核 __asm { mov edx, dest mov ecx, exchange_value mov eax, compare_value LOCK_IF_MP(mp) cmpxchg dword ptr [edx], ecx } }
linux_x86中,实现如下
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; }
可以看到最终都是使用操作系统对应的指令来完成
都在哪儿用了
可以看到Atomic的实现就是用的CAS,比如AtomicInteger的incrementAndGet
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
这种一直循环的操作也称作自旋
CAS的缺点如果一直没有成功,则一直循环,给CPU带来很大的开销。
只能是一个变量
ABA问题。一个变量取值为A,恰巧另一个线程将它换成了B然后又换回来了,这个时候再读取还是A,实际上是改变了值。java自身提供了AtomicStampedReference来解决这个问题,原理是添加一个额外的版本来做判断
源码来自jdk1.7
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72727.html
摘要:方法由两个参数,表示期望的值,表示要给设置的新值。操作包含三个操作数内存位置预期原值和新值。如果处的值尚未同时更改,则操作成功。中就使用了这样的操作。上面操作还有一点是将事务范围缩小了,也提升了系统并发处理的性能。 这是java高并发系列第21篇文章。 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库...
摘要:耐心看完的你或多或少会有收获并发的核心就是包,而的核心是抽象队列同步器,简称,一些锁啊信号量啊循环屏障啊都是基于。 耐心看完的你或多或少会有收获! Java并发的核心就是 java.util.concurrent 包,而 j.u.c 的核心是AbstractQueuedSynchronizer抽象队列同步器,简称 AQS,一些锁啊!信号量啊!循环屏障啊!都是基于AQS。而 AQS 又是...
摘要:这个规则比较好理解,无论是在单线程环境还是多线程环境,一个锁处于被锁定状态,那么必须先执行操作后面才能进行操作。线程启动规则独享的方法先行于此线程的每一个动作。 1. 指令重排序 关于指令重排序的概念,比较复杂,不好理解。我们从一个例子分析: public class SimpleHappenBefore { /** 这是一个验证结果的变量 */ private st...
摘要:有了这个基础,才能发挥作用,使得在节点取消和异常时能够保证队列在多线程下的完整性。 Doug Lea是JDK中concurrent工具包的作者,这位大神是谁可以自行google。 本文浅析ReentrantLock(可重入锁)的原理 Lock接口 showImg(https://segmentfault.com/img/bV2671?w=276&h=176); Lock接口定义了这几个...
阅读 1981·2019-08-30 15:54
阅读 3532·2019-08-30 15:52
阅读 1821·2019-08-29 17:20
阅读 2512·2019-08-29 17:08
阅读 2346·2019-08-26 13:24
阅读 780·2019-08-26 11:59
阅读 2780·2019-08-23 14:50
阅读 610·2019-08-23 14:20