版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yu280265067/article/details/50824881
java并发编程也研究了一段时间了,对CAS的原理总是不太理解,今天再研究了一下,记录一些自己的理解。
说到CAS,再java中的某些情况下,甚至jdk1.5以后的大多数情况,并发编程都是用CAS实现的,那么CAS到底如何能够实现锁的功能呢?
拿a++操作举例
1、ABA问题
3、会增加程序测试的复杂度,稍不注意就会出现问题。
总结
可以用CAS在无锁的情况下实现原子操作,但要明确应用场合,非常简单的操作且又不想引入锁可以考虑使用CAS操作,当想要非阻塞地完成某一操作也可以考虑CAS。不推荐在复杂操作中引入CAS,会使程序可读性变差,且难以测试,同时会出现ABA问题。
说到CAS,再java中的某些情况下,甚至jdk1.5以后的大多数情况,并发编程都是用CAS实现的,那么CAS到底如何能够实现锁的功能呢?
拿a++操作举例
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
这里面的compareAndSet的功能为,a与current比较,如果相等则把a的值变为next;这时候可以保证在int next = current + 1;与if();之间不会被其他线程抢占(因为a的值在这段时间内没有变),如果被抢占则会做自旋操作。这就在某种程度上可以实现原子性操作。
这是一种不加锁而实现操作原子化的一种巧妙的编程方式,不仅在java的jvm种,甚至在操作系统的底层并发实现机制中也有CAS的大量应用。
但是这种方式有没有缺点呢?
当然也会有:1、ABA问题
CAS操作容易导致ABA问题,也就是在做a++之间,a可能被多个线程修改过了,只不过回到了最初的值,这时CAS会认为a的值没有变。a在外面 逛了一圈回来,你能保证它没有做任何坏事,不能!!也许它讨闲,把b的值减了一下,把c的值加了一下等等,更有甚者如果a是一个对象,这个对象有可能是新 创建出来的,a是一个引用呢情况又如何,所以这里面还是存在着很多问题的,解决ABA问题的方法有很多,可以考虑增加一个修改计数,只有修改计数不变的且 a值不变的情况下才做a++,也可以考虑引入版本号,当版本号相同时才做a++操作等,这和事务原子性处理有点类似!
3、会增加程序测试的复杂度,稍不注意就会出现问题。
总结
可以用CAS在无锁的情况下实现原子操作,但要明确应用场合,非常简单的操作且又不想引入锁可以考虑使用CAS操作,当想要非阻塞地完成某一操作也可以考虑CAS。不推荐在复杂操作中引入CAS,会使程序可读性变差,且难以测试,同时会出现ABA问题。