Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.
主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁.
今天有时间跟踪了一下AtomicInteger的incrementAndGet的实现.
本人对并发编程也不是特别了解, 在这里就是做个笔记, 方便以后再深入研究.
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
6. 最后再贴一下x86的cmpxchg指定
CPU: I486+
Type of Instruction: User
Instruction: CMPXCHG dest, src
Description: Compares the accumulator with dest. If equal the "dest"
is loaded with "src", otherwise the accumulator is loaded
with "dest".
Flags Affected: AF, CF, OF, PF, SF, ZF
CPU mode: RM,PM,VM,SMM
+++++++++++++++++++++++
Clocks:
CMPXCHG reg, reg 6
CMPXCHG mem, reg 7 (10 if compartion fails)
主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁.
今天有时间跟踪了一下AtomicInteger的incrementAndGet的实现.
本人对并发编程也不是特别了解, 在这里就是做个笔记, 方便以后再深入研究.
1. incrementAndGet的实现
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
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);
}
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);
* 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
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
}
}
// 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
6. 最后再贴一下x86的cmpxchg指定
Opcode CMPXCHG
CPU: I486+
Type of Instruction: User
Instruction: CMPXCHG dest, src
Description: Compares the accumulator with dest. If equal the "dest"
is loaded with "src", otherwise the accumulator is loaded
with "dest".
Flags Affected: AF, CF, OF, PF, SF, ZF
CPU mode: RM,PM,VM,SMM
+++++++++++++++++++++++
Clocks:
CMPXCHG reg, reg 6
CMPXCHG mem, reg 7 (10 if compartion fails)
相关推荐
这些类的原子操作,如`getAndSet`、`compareAndExchange`等,都是基于`Unsafe`的CAS操作实现的。 下面是一个简单的示例,展示如何使用`Unsafe`进行CAS操作: ```java import com.walking.juc.util.UnsafeUtil; ...
if (ref.compareAndSet(obj, new MyObject(), stamp, stamp + 1)) { System.out.println("更新成功"); } else { System.out.println("更新失败,有其他线程修改了引用或版本号"); } ``` **四、优缺点** 优点:...
CAS操作 CAS是单词compare and set的缩写,意思是指在set之前先比较该值有没有变化,只有在没变的情况下才对其赋值。 我们常常做这样的操作 ... if(a.compareAndSet(expect,a+1)) { doSomeThing1();
Atomic类提供了一些原子操作的方法,如compareAndSet()方法,可以实现CAS操作。 自旋锁的优点是可以提高系统的性能,因为它可以减少锁争用的次数。自旋锁的缺点是可能会导致busy waiting的问题,即线程会一直等待锁...
原子方式体现在何处,就体现在compareAndSet上,看看compareAndSet是如何实现的:public final boolean compareAndSet(int expect, int update) { ... } 不出所料,它就是采用的Unsafe类的CAS操作完成的。 a++操作...
例如,`compareAndSet()`方法就是用于执行CAS操作,它的使用通常包括以下步骤: 1. 读取当前值:线程首先读取变量的当前值。 2. 拟定新值:根据当前值计算出期望的新值。 3. CAS更新:使用`compareAndSet()`尝试将...
这些类提供了无锁的原子操作,如`compareAndSet()`、`addAndGet()`等方法。以`AtomicInteger`为例,`addAndGet()`方法通过循环执行CAS操作,不断尝试将预期值与新值进行比较并交换,直到成功。这样,即使在高并发...
如果在检查旧值和尝试更新之间,有其他线程改变了变量,`compareAndSet()`会失败,从而避免了数据的不一致性。 清单1展示了使用`synchronized`关键字实现的线程安全计数器,每次`increment()`方法都会获取锁,完成...
- `boolean compareAndSet(int i, int expect, int update)`:如果数组中索引`i`处的值等于`expect`,则以原子方式将其设置为`update`。 3. **AtomicReference** - `V getAndSet(V newValue)`:以原子方式设置为...
CAS(Compare-And-Swap)是一种无锁机制,用于实现线程安全的更新操作。CAS 操作包括三个参数:expected value、new value 和当前值。如果当前值等于 expected value,那么就将当前值更新为 new value。 6. 线程池 ...
- `compareAndSet(int expect, int update)`:如果当前值等于预期值,则将其设置为给定的更新值,并返回`true`;否则返回`false`。 - `decrementAndGet()`:以原子方式将当前值减1。 - `get()`:获取当前值。 - ...
这些类提供了一些原子操作,如incrementAndGet()、compareAndSet()等,这些操作都是CAS操作的实现。 下面是使用AtomicInteger类实现CAS操作的示例代码: ```java public class T03_AtomicInteger { AtomicInteger ...
}}对AtomicInteger进行+1操作,循环里,会将当前值和+1后的目标值传入compareAndSet,直到成功才跳出方法。 compareAndSet是不是很熟悉呢,接着来看看它的代码。// setup to use Unsafe.compareAndSwapInt for ...
if (compareAndSet(current, current - 1)) { return true; } current = token; if (current <= 0 && expect > 0) { synchronized (lock) { try { lock.wait(expect); } catch (InterruptedException e) { ...
```AtomicStampedReference```来解决ABA问题,类中的```compareAndSet```方法作用首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果相等,以原子方式将该引用和标记的值设置为给定的更新值。
例如,AtomicInteger类提供了如compareAndSet、getAndIncrement等原子操作方法,这些方法内部都使用了CAS算法。 AtomicInteger类的使用示例: ```java AtomicInteger atomicInteger = new AtomicInteger(0); // ...
atomicStampedReference.compareAndSet(100, 101, stamp, stamp + 1); // ... atomicStampedReference.compareAndSet(101, 100, stamp, stamp + 1); ``` 在这个例子中,每个修改都会检查并更新版本号,确保了即使值...
CAS就这?一. CAS是什么?二. CAS底层原理2.1 JMM内存模型(涉及到的知识点)2.2 CAS底层2.3 总结与应用三.... => compareAndSet 比较并交换 */ public class CASTest { public static void main(Strin