第一章 AtomicInteger中涉及到CAS的函数
经过对AtomicInteger源代码的查看,发现用到CAS主要是下面的函数,观察下面的函数,发现主要是用到了这个几个unsafe的函数,unsafe是封装了原子操作的JNI,使用unsafe能把操作原子化,原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。
unsafe.getAndSetInt
unsafe.compareAndSwapInt
unsafe.getAndAddInt
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
第二章 分析unsafe的几个方法
观察getAndSetInt、getAndAddInt的源码,发现它们都调用了compareAndSwapInt函数,那么可以看到传入了四个参数,
第一个参数代表要修改字段所在的对象,如我们其实传入了this,this也就代表AtomicInteger。
第二个参数代表valueOffset代表要修改字段相对于我们的对象在内存中的偏移量,如我们要修改AtomicInteger中的value,传入的就是value的偏移量,字段的偏移量在AtomicInteger的静态代码块(如下)中计算出(感觉这也间接说明静态字段在内存中的位置不会变?)
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
第三个参数代表修改前的值,即我们期望的修改前的值。
第四个参数代表修改后的值,即我们期望的修改后的值。
第三章 CAS的缺陷
参考:https://www.cnblogs.com/renqiqiang/articles/10129354.html
3.1 ABA问题
问题描述:线程t1将它的值从A变为B,再从B变为A。同时有线程t2要将值从A变为C。但CAS检查的时候会发现没有改变,但是实质上它已经发生了改变 。可能会造成数据的缺失。
解决方法:CAS还是类似于乐观锁,同数据乐观锁的方式给它加一个版本号或者时间戳,如AtomicStampedReference
3.2 多次自旋导致效率下降
问题描述:多个线程争夺同一个资源时,如果自旋一直不成功,将会一直占用CPU。
解决方法:破坏掉for死循环,当超过一定时间或者一定次数时,return退出。JDK8新增的LongAddr,和ConcurrentHashMap类似的方法。当多个线程竞争时,将粒度变小,将一个变量拆分为多个变量,达到多个线程访问多个资源的效果,最后再调用sum把它合起来。
虽然base和cells都是volatile修饰的,但感觉这个sum操作没有加锁,可能sum的结果不是那么精确。
3.3 多变量共享一致性问题
我们之前都是对一个变量使用循环CAS,如果对多个变量操作,1. 可以加锁来解决。2 .封装成对象类解决。
————————————————
版权声明:本文为优快云博主「逆袭的小学生」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/q610376681/article/details/108905300
404

被折叠的 条评论
为什么被折叠?



