Java------多线程_高级主题_CAS_原子操作(十七)
CAS
锁分为两类:
1.悲观锁:synchronized是独占锁即悲观锁,会导致其他所有需要锁的线程挂起,等待持有锁的线程释放锁。
2.乐观锁:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
根据不同的角度也有不同的分类方法,在可沿用性的角度,分为可重入和不可重入。还可以分为公平锁和不公平锁,所谓是否公平是锁在应用时会加入到队列中,如果是按照先后顺序去使用这个锁,就叫做公平锁,如果不按照队列顺序叫做不公平锁。还有自旋锁、阻塞锁等等。
Compare and Swap 比较并交换:
乐观锁的实现:
1.有三个值:一个当前内存值V、旧的预期值A、将更新的值B,先获取到内存当中当前的内存值V,再将内存值V和原值A进行比较,要是相等就修改为要修改的值B并返回true,否则什么都不做,并返回false;
2.CAS是一组原子操作,不会被外部打断。
3.属于硬件级别的操作(利用CPU的CAS指令,同时借助JNI来完成的非阻塞算法),效率比加锁操作度高。
4.ABA问题:如果变量V初次读取的时候是A,并且在准备赋值的时候检查到它仍然是A,那能说明它的值没有被其他线程修改过吗?如果在这段期间曾被修改成B,然后又改为A,那CAS操作就会误认为它从来没有被修改过。
通过不断地比较版本,重点在于比较版本,交换值。
Atomic都是用了CAS的思想。
案例一:扣库存
package cooperation;
import java.util.concurrent.atomic.AtomicInteger;
/**
* CAS:比较并交换
*/
public class CAS {
//已经实现CAS的integer类,stock表库存
private static AtomicInteger stock = new AtomicInteger(5);
public static void main(String[] args) {
for (int i = 0 ;i<5;i++){
new Thread(() ->{
//模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//源码中使用native,就是JNI技术,CPU硬件层面实现,使用CAS操作,Atomic都用了CAS思想
Integer left = stock.decrementAndGet();
if (left<1){
System.out.println("抢完了");
return;
}
System.out.println(Thread.currentThread().getName()+"抢了一件商品");
System.out.println("还剩下"+left);
}).start();
}
}
}