java中的CAS
2016-07-04 16:26
507 查看
转自:http://www.blogjava.net/mstar/archive/2013/04/24/398351.html
Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.
主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁.
1. incrementAndGet的实现
首先可以看到他是通过一个无限循环(spin)直到increment成功为止.
循环的内容是
1.取得当前值
2.计算+1后的值
3.如果当前值还有效(没有被)的话设置那个+1后的值
4.如果设置没成功(当前值已经无效了即被别的线程改过了), 再从1开始.
2. compareAndSet的实现
直接调用的是UnSafe这个类的compareAndSwapInt方法
全称是sun.misc.Unsafe. 这个类是Oracle(Sun)提供的实现. 可以在别的公司的JDK里就不是这个类了
3. compareAndSwapInt的实现
可以看到, 不是用Java实现的, 而是通过JNI调用操作系统的原生程序.
4. compareAndSwapInt的native实现
如果你下载了OpenJDK的源代码的话在hotspot\src\share\vm\prims\目录下可以找到unsafe.cpp
可以看到实际上调用Atomic类的cmpxchg方法.
5. Atomic的cmpxchg
这个类的实现是跟操作系统有关, 跟CPU架构也有关, 如果是windows下x86的架构
实现在hotspot\src\os_cpu\windows_x86\vm\目录的atomic_windows_x86.inline.hpp文件里
在这里可以看到是用嵌入的汇编实现的, 关键CPU指令是 cmpxchg
到这里没法再往下找代码了. 也就是说CAS的原子性实际上是CPU实现的. 其实在这一点上还是有排他锁的. 只是比起用synchronized, 这里的排他时间要短的多. 所以在多线程情况下性能会比较好.
代码里有个alternative for InterlockedCompareExchange
这个InterlockedCompareExchange是WINAPI里的一个函数, 做的事情和上面这段汇编是一样的 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560%28v=vs.85%29.aspx
AtomicInteger的源码说明
关于lazySet的说明: http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-vs-set
Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.
主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁.
1. incrementAndGet的实现
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
首先可以看到他是通过一个无限循环(spin)直到increment成功为止.
循环的内容是
1.取得当前值
2.计算+1后的值
3.如果当前值还有效(没有被)的话设置那个+1后的值
4.如果设置没成功(当前值已经无效了即被别的线程改过了), 再从1开始.
2. compareAndSet的实现
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
直接调用的是UnSafe这个类的compareAndSwapInt方法
全称是sun.misc.Unsafe. 这个类是Oracle(Sun)提供的实现. 可以在别的公司的JDK里就不是这个类了
3. compareAndSwapInt的实现
/** * Atomically update Java variable to <tt>x</tt> if it is currently * holding <tt>expected</tt>. * @return <tt>true</tt> if successful */ public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
可以看到, 不是用Java实现的, 而是通过JNI调用操作系统的原生程序.
4. compareAndSwapInt的native实现
如果你下载了OpenJDK的源代码的话在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; UNSAFE_END
可以看到实际上调用Atomic类的cmpxchg方法.
5. Atomic的cmpxchg
这个类的实现是跟操作系统有关, 跟CPU架构也有关, 如果是windows下x86的架构
实现在hotspot\src\os_cpu\windows_x86\vm\目录的atomic_windows_x86.inline.hpp文件里
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { // alternative for InterlockedCompareExchange 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 } }
在这里可以看到是用嵌入的汇编实现的, 关键CPU指令是 cmpxchg
到这里没法再往下找代码了. 也就是说CAS的原子性实际上是CPU实现的. 其实在这一点上还是有排他锁的. 只是比起用synchronized, 这里的排他时间要短的多. 所以在多线程情况下性能会比较好.
代码里有个alternative for InterlockedCompareExchange
这个InterlockedCompareExchange是WINAPI里的一个函数, 做的事情和上面这段汇编是一样的 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560%28v=vs.85%29.aspx
AtomicInteger的源码说明
/**
内部使用一个int字段用来表示一个value值,借助compareAndSwap实现原子更新
**/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
//这个值标示了value在对象中的位置,compareAndSet的时候会使用到这个值
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
/**
* Gets the current value.
*
* @return the current value
*/
public final int get() {
return value;
}
/**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(int newValue) {
value = newValue;
}
/**
* 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);
}
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
/**
* 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(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 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 previous value
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* Atomically decrements by one the current value.
*
* @return the previous value
*/
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
}
/**
* 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; } }
/**
* Atomically decrements by one the current value.
*
* @return the updated value
*/
public final int decrementAndGet() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return next;
}
}
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}
}
/**
* Returns the String representation of the current value.
* @return the String representation of the current value.
*/
public String toString() {
return Integer.toString(get());
}
public int intValue() {
return get();
}
public long longValue() {
return (long)get();
}
public float floatValue() {
return (float)get();
}
public double doubleValue() {
return (double)get();
}
关于lazySet的说明: http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-vs-set
相关文章推荐
- Java模拟Windows的Event
- 个人学习java的真实经历!
- Eclipse Java注释模板设置详解——版权声明
- jsp提交表单与后台java处理表单
- java语言基础入门——变量、数据及常量的介绍
- java基础之----封装(private)
- spring 事物控制---多数据源与 atomikos 分布式事务配置(接之前未完成的部分)
- Java开发中的23种设计模式详解(转)
- org.springframework.beans.MethodInvocationException: Property 'cacheManager' threw exception; neste
- 对于java学习中的date与String转换demo
- Java Lambda 表达式介绍
- Java基础——super的几种用法并与this的区别
- Spring 框架简介
- Java编写的断点续传的一个Demo示例
- Java8 Stream流操作在用户系统中的妙用
- Groovy with eclipse-tutorial
- java 去除jsonarray里面jsonarray的重复和合并数据
- (基于Java)编写编译器和解释器-第2章:框架I:编译器和解释器-第三部分(连载)
- 对象导论之抽象过程
- sikuli 相关遇见过的问题汇总