Java CAS(Compare And Swap)的一点理解
CAS: Compare And Swap, 即比较和替换。
思想: CAS的比较、替换操作是非阻塞操作, 它有3个参数分别为内存值、预期值和更新值。 当内存值和预期值匹配时则更新, 不匹配时直接返回。
PS: CAS比synchronized效率要好, 因为CAS是c语言实现的cpu锁机制, synchronized是Java锁。
简单的说CAS提供了一种实现原子操作的方法, 都封装在sun.misc.Unsafe类里。 而在实际开发过程中, 并不建议直接操作Unsafe类, 而且使用基于Unsafe类实现的各个派生类。
这些类都提供了原子操作, 假设使用AtomicInteger模拟生产者消费者模式。
AtomicInteger object = new AtomicInteger(0);
for (int i = 0; i < 4; i++) {
//逻辑上的生产者, 值从0到1
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (Exception ex) {
}
System.out.println("判断0线程,当前值是"+ object.get()
+ ", 返回值"+ object.compareAndSet(0, 1)); //compare函数是非阻塞
}
}
}.start();
//逻辑上的消费者, 值从1到0
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (Exception ex) {
}
System.out.println("判断1线程,当前值是" + object.get()
+ ", 返回值" + object.compareAndSet(1, 0)); //非阻塞
}
}
}.start();
}
4个生产者线程、4个开发者线程。 生产者线程的作用是0到1, 消费者线程的作用是1到0。 代码里并没有同步控制逻辑(即没有synchronized/Lock), 运行程序看看效果。判断0线程,当前值是0, 返回值true
判断0线程,当前值是0, 返回值true
判断1线程,当前值是0, 返回值false
判断1线程,当前值是1, 返回值true
判断0线程,当前值是0, 返回值true
判断1线程,当前值是1, 返回值true
判断1线程,当前值是1, 返回值true
判断0线程,当前值是1, 返回值false
判断0线程,当前值是0, 返回值true
判断0线程,当前值是1, 返回值false
判断1线程,当前值是1, 返回值true
判断1线程,当前值是0, 返回值false
判断0线程,当前值是0, 返回值true
判断1线程,当前值是1, 返回值true
程序运行正常, 并没有报共享冲突错误。原理:
1、 volatile关键字保证这8个线程操作的是同一块内存;
2、 原子性操作compareAndSet即比较并更新, 是在native层实现的, 原理见下面的2篇博客。
CAS里所有ABA问题其实就是值在改回来前不知道发生了什么, 例如: 你读取的值是1, 但前面可能经历了3、2等值的情况。
使用AtomicStampedReference可以解决ABA问题, 因为每次更新值时都有一个时间戳。 在compareAndSet时既要比较值,也要比较时间戳是否一致。
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
参考博客:
https://www.jianshu.com/p/24ffe531e9ee
http://zl198751.iteye.com/blog/1848575
上一篇: 使用mint-ui在手机端做出三级联动
下一篇: 机房管理系统vb与excel链接2