Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX
转自:http://brokendreams.iteye.com/blog/2250109
- 原子量和普通变量相比,主要体现在读写的线程安全上。对原子量的是原子的(比如多线程下的共享变量i++就不是原子的),由CAS操作保证原子性。对原子量的读可以读到最新值,由volatile关键字来保证可见性。
- 原子量多用于数据统计(如接口调用次数)、一些序列生成(多线程环境下)以及一些同步数据结构中。
- 首先,原子量的一些较底层的操作都是来自sun.misc.Unsafe类,所以原子量内部有一个Unsafe的静态引用。
private static final Unsafe unsafe = Unsafe.getUnsafe();
- 接下来,先看下AtomicInteger的源码。
private volatile int value;
/*
* Implementation of class sun.misc.Unsafe
*/
...
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;
UNSAFE_END
这里调用了Atomic的cmpxchg方法,继续找一下。这个方法定义在hotspot/share/vm/runtime/atomic.hpp 中,实现在hotspot/share/vm/runtime/atomic.cpp中,最终实现取决于底层OS,比如linux x86,实现内联在hotspot部分代码os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp:
// Adding a lock prefix to an instruction on MP machine
#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
...
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;
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
最后,AtomicInteger还有一个方法,lazySet:
/**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
{CC"putOrderedInt", CC"("OBJ"JI)V", FN_PTR(Unsafe_SetOrderedInt)},
...
// The non-intrinsified versions of setOrdered just use setVolatile
UNSAFE_ENTRY(void, Unsafe_SetOrderedInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint x))
UnsafeWrapper("Unsafe_SetOrderedInt");
SET_FIELD_VOLATILE(obj, offset, jint, x);
UNSAFE_END
注:上面有句注释,说明这只是一个非内联的setOrdered方法的实现,使用了setVolatile(和setVolatile一样的效果)。
#define SET_FIELD_VOLATILE(obj, offset, type_name, x) \
oop p = JNIHandles::resolve(obj); \
OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x);
inline void OrderAccess::release_store_fence(volatile jint* p, jint v) {
__asm__ volatile ( "xchgl (%2),%0"
: "=r" (v)
: "0" (v), "r" (p)
: "memory");
}
do_intrinsic(_putOrderedInt, sun_misc_Unsafe,putOrderedInt_name, putOrderedInt_signature,F_RN)
然后找到hotspot/src/share/vm/opto/library_call.cpp中找到相应实现:
case vmIntrinsics::_putOrderedInt:
return inline_unsafe_ordered_store(T_INT);
...
bool LibraryCallKit::inline_unsafe_ordered_store(BasicType type) {
// This is another variant of inline_unsafe_access, differing in
// that it always issues store-store ("release") barrier and ensures
// store-atomicity (which only matters for "long").
if (callee()->is_static()) return false; // caller must have the capability!
...//省略不重要的部分
insert_mem_bar(Op_MemBarRelease);
insert_mem_bar(Op_MemBarCPUOrder);
// Ensure that the store is atomic for longs:
bool require_atomic_access = true;
Node* store;
if (type == T_OBJECT) // reference stores need a store barrier.
store = store_oop_to_unknown(control(), base, adr, adr_type, val, type);
else {
store = store_to_memory(control(), adr, val, type, adr_type, require_atomic_access);
}
insert_mem_bar(Op_MemBarCPUOrder);
return true;
}
instruct membar_release() %{
match(MemBarRelease);
ins_cost(400);
size(0);
format %{ "MEMBAR-release ! (empty encoding)" %}
ins_encode( );
ins_pipe(empty);
%}
...
instruct membar_volatile(eFlagsReg cr) %{
match(MemBarVolatile);
effect(KILL cr);
ins_cost(400);
format %{
$$template
if (os::is_MP()) {
$$emit$$"LOCK ADDL [ESP + #0], 0\t! membar_volatile"
} else {
$$emit$$"MEMBAR-volatile ! (empty encoding)"
}
%}
ins_encode %{
__ membar(Assembler::StoreLoad);
%}
ins_pipe(pipe_slow);
%}
- 再看下AtomicBoolean的源码。
private volatile int value;
/**
* Creates a new {@code AtomicBoolean} with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicBoolean(boolean initialValue) {
value = initialValue ? 1 : 0;
}
- 继续看下AtomicLong的源码。
/**
* Records whether the underlying JVM supports lockless
* compareAndSwap for longs. While the Unsafe.compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
/**
* Returns whether underlying JVM supports lockless CompareAndSet
* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
*/
private static native boolean VMSupportsCS8();
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile long value;
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(long expect, long update) {
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
{CC"compareAndSwapLong", CC"("OBJ"J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, ...
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x))
UnsafeWrapper("Unsafe_CompareAndSwapLong");
Handle p (THREAD, JNIHandles::resolve(obj));
jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
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;
}
UNSAFE_END
从实现中可以看到,如果平台不支持8字节的CAS操作,就会加锁然后进行设置操作;如果支持,就会调用Atomic::cmpxchg方法,方法实现可以 参考具体平台内联代码hotspot/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp:
// Adding a lock prefix to an instruction on MP machine
#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) {
bool mp = os::is_MP();
__asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
: "cc", "memory");
return exchange_value;
}
/**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(long newValue) {
unsafe.putOrderedLong(this, valueOffset, newValue);
}
- {CC"putOrderedLong", CC"("OBJ"JJ)V", FN_PTR(Unsafe_SetOrderedLong)},
- ...
- UNSAFE_ENTRY(void, Unsafe_SetOrderedLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x))
- UnsafeWrapper("Unsafe_SetOrderedLong");
- #if defined(SPARC) || defined(X86)
- // Sparc and X86 have atomic jlong (8 bytes) instructions
- SET_FIELD_VOLATILE(obj, offset, jlong, x);
- #else
- // Keep old code for platforms which may not have atomic long (8 bytes) instructions
- {
- if (VM_Version::supports_cx8()) {
- SET_FIELD_VOLATILE(obj, offset, jlong, x);
- }
- else {
- Handle p (THREAD, JNIHandles::resolve(obj));
- jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
- ObjectLocker ol(p, THREAD);
- *addr = x;
- }
- }
- #endif
- UNSAFE_END
从实现上看,如果平台是SPARC或者X86或者平台支持8字节CAS,就相当于执行了一个volatile write;否则,加锁写。
- do_intrinsic(_putOrderedLong, sun_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_RN) \
然后找到hotspot/src/share/vm/opto/library_call.cpp中找到相应实现。
- case vmIntrinsics::_putOrderedLong:
- return inline_unsafe_ordered_store(T_LONG);
- ...
- ol LibraryCallKit::inline_unsafe_ordered_store(BasicType type) {
- // This is another variant of inline_unsafe_access, differing in
- // that it always issues store-store ("release") barrier and ensures
- // store-atomicity (which only matters for "long").
- if (callee()->is_static()) return false; // caller must have the capability!
- ...//忽略不重要部分
- // Ensure that the store is atomic for longs:
- bool require_atomic_access = true;
- Node* store;
- if (type == T_OBJECT) // reference stores need a store barrier.
- store = store_oop_to_unknown(control(), base, adr, adr_type, val, type);
- else {
- store = store_to_memory(control(), adr, val, type, adr_type, require_atomic_access);
- }
- insert_mem_bar(Op_MemBarCPUOrder);
- return true;
从代码的注释上可以发现,require_atomic_access设置为true,为了保证long写操作的原子性。继续跟代码,找到hotspot/src/share/vm/opto/graphKit.cpp:
- Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
- int adr_idx,
- bool require_atomic_access) {
- assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
- const TypePtr* adr_type = NULL;
- debug_only(adr_type = C->get_adr_type(adr_idx));
- Node *mem = memory(adr_idx);
- Node* st;
- if (require_atomic_access && bt == T_LONG) {
- st = StoreLNode::make_atomic(C, ctl, mem, adr, adr_type, val);
- } else {
- st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt);
- }
- st = _gvn.transform(st);
- set_memory(st, adr_idx);
- // Back-to-back stores can only remove intermediate store with DU info
- // so push on worklist for optimizer.
- if (mem->req() > MemNode::Address && adr == mem->in(MemNode::Address))
- record_for_igvn(st);
- return st;
- }
可见,这里会针对long做原子写操作(这里的原子操作应该指的是将long的高4字节和低4字节的操作合并成一个原子操作,比如某些平台不支持非volatile的long/double域的原子操作)。
- 最后看下AtomicReference的源码。
- public class AtomicReference<V> implements java.io.Serializable {
- private static final long serialVersionUID = -1848883965231344442L;
- private static final Unsafe unsafe = Unsafe.getUnsafe();
- private static final long valueOffset;
- static {
- try {
- valueOffset = unsafe.objectFieldOffset
- (AtomicReference.class.getDeclaredField("value"));
- } catch (Exception ex) { throw new Error(ex); }
- }
- private volatile V value;
重点看一下内部调用的unsafe的compareAndSwapObject和putOrderedObject方法,先看一下compareAndSwapObject:
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- * @param expect the expected value
- * @param update the new value
- * @return true if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public final boolean compareAndSet(V expect, V update) {
- return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
- }
在unsafe.cpp中可以找到实现:
- {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)},
- ...
- UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
- UnsafeWrapper("Unsafe_CompareAndSwapObject");
- oop x = JNIHandles::resolve(x_h);
- oop e = JNIHandles::resolve(e_h);
- oop p = JNIHandles::resolve(obj);
- HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);
- if (UseCompressedOops) {
- update_barrier_set_pre((narrowOop*)addr, e);
- } else {
- update_barrier_set_pre((oop*)addr, e);
- }
- oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
- jboolean success = (res == e);
- if (success)
- update_barrier_set((void*)addr, x);
- return success;
- UNSAFE_END
可以看到里面实际上是执行oopDesc::atomic_compare_exchange_oop这个方法。找到hotspot/src/share/vm/oops/oop.inline.hpp中该方法实现:
- inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
- volatile HeapWord *dest,
- oop compare_value) {
- if (UseCompressedOops) {
- // encode exchange and compare value from oop to T
- narrowOop val = encode_heap_oop(exchange_value);
- narrowOop cmp = encode_heap_oop(compare_value);
- narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
- // decode old from T to oop
- return decode_heap_oop(old);
- } else {
- return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
- }
- }
cmpxchg之前分析过,看看cmpxche_ptr,找到hotspot/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp中实现:
- inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) {
- return (intptr_t)cmpxchg((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value);
- }
- inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) {
- bool mp = os::is_MP();
- __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
- : "=a" (exchange_value)
- : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
- : "cc", "memory");
- return exchange_value;
- }
就是(多核下带lock前缀的)cmpxchgq命令了。
Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX的更多相关文章
- Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ...
- Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer
功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDow ...
- Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue
功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ...
- Jdk1.6 JUC源码解析(7)-locks-ReentrantLock
功能简介: Java代码层面提供的锁机制,可做为Synchronized(jvm内置)的替代物,和Synchronized一样都是可重入的. 与Synchronized相比较而言,ReentrantL ...
- 【JUC源码解析】ScheduledThreadPoolExecutor
简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...
- 【JUC源码解析】SynchronousQueue
简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...
- 【JUC源码解析】ForkJoinPool
简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ...
- 【JUC源码解析】DelayQueue
简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ...
- 【JUC源码解析】CyclicBarrier
简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ...
随机推荐
- PMP和PRINCE2的价值各是什么?PRINCE2的含金量如何?PMP和prince2有什么区别?
很多学员朋友会问我同样的问题:"PMP和PRINCE2到底有什么区别?哪个含金量更高?"看来,这是所有要参加认证的朋友普遍关心的问题,我将根据自己的切身体会,从三个方面回答这个问题 ...
- xlrd的使用详细介绍以及基于Excel数据参数化实例详解
1.安装xlrd xlrd是python用于读取excel的第三方扩展包,所以在使用xlrd前,需要使用以下命令来安装xlrd.pip install xlrd 在使用这个命令之前先确定自己有没有安装 ...
- div背景图片或颜色不显示的解决办法
背景图片不显示的原因: 1. css没有被调用 2. css图片地址不对 3. div的高度没有固定,是auto.没有设值或者高度不够 4. div被嵌套 5. div代码不规范 解决办法: (1)D ...
- 高并发场景之RabbitMQ篇
上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能解决问题,后来采用Redis队 ...
- JavaScript基础学习(六)—函数
一.函数的定义 1.function语句形式 //1.function语句式 function test1(){ alert("I am test1"); } test1(); 2 ...
- nlog学习使用
最近有不少朋友推荐我用NLog.我以前都是自己写txt的文本输出log,以前别人用log4net的时候看那个配置文件,看得我一阵烦,我比较喜欢约定胜于配置的组件.这次玩了一波NLog,,相当不错.一下 ...
- 1001. Exponentiation高精度运算总结
解题思路 这道题属于高精度乘法运算,要求输入一个实数R一个指数N,求实数R的N次方,由于R有5个数位,而N又特别大,因此用C++自带的数据类型放不下. 解题思路是通过数组储存每次乘积结果和底数的每一位 ...
- java类集框架(ArrayList,LinkedList,Vector区别)
主要分两个接口:collection和Map 主要分三类:集合(set).列表(List).映射(Map)1.集合:没有重复对象,没有特定排序方式2.列表:对象按索引位置排序,可以有重复对象3.映射: ...
- pl/sql 笔记之存储过程、函数、包、触发器(下)
一.存储过程.存储函数 1.What's This? ①.ORACLE 提供可以把 PL/SQL 程序存储在数据库中,并可以在任何地方来运行它.这样就叫存储过程或函数. ②.存储过程.存储函数的唯 ...
- AspNetCore - MVC实战系列(一)
本章开篇先简单介绍下最近两周自己利用业余时间做的一个图片收集网站,当然这个是靠用户自己上传来收集不是去抓某些个网站的图片,那样没意义,这里我取名为“爱留图”:该网站的简单介绍大家可以参考下上篇的内容爱 ...