Java中的CAS
2021-01-20 05:15
标签:com 源码 inter dex 作用 class 标记 正是 目的 引用上一篇JMM中的开篇代码,再次针对性分析。 执行main方法,开启10000个并发线程,可以看到最后输出的结果不一定是10000,前面也讲到了i++不是一个原子操作,原因i++在底层实际分三步执行:1、从主内存拷贝变量副本到工作内存;2,执行自增操作;3,写回主内存,任何一阶段都存在被中断的风险,也就导致每个线程对i的操作不一定成功+1。而共享变量引入volatile修饰,前面也介绍到volatile只能保证共享变量改变时的可见性和有序性。那么怎样保证原子性呢,想到自然是synchronized加锁,然而sync锁机制会引起以下问题: (1)在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。 (2)一个线程持有锁会导致其它所有需要此锁的线程挂起。 (3)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。 那么既然sync会引起性能的问题,有没有好点的方式去解决这个既能保证原子性又能解决sync引起的性能问题呢?Java1.5并发包原子操作类(Atomic开头)解决了这个问题。看以下代码: 看到compareAndSwapInt了,这就是CAS,好吧,这正是今天 的主角。说到CAS先讲下两个锁:悲观锁和乐观锁 sync也是一种独占锁,而独占锁正是悲观锁的表现。独占锁,如读锁,写锁,数据库的行级锁和表级锁。它会引起其他需要同一把锁的线程挂起,等待当前持有锁资源的线程释放。 CAS,Compare And Swap,释义比较并替换。CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。CAS也称为自旋锁,在一个(死)循环【for(;;)】里不断进行CAS操作,直到成功为止(自旋操作),实际上,CAS也是一种乐观锁。 前面也讲到CAS是为解决非原子操作引起的并发安全问题(解决原子操作问题),同时优化性能(提高性能)而产生,CAS的原子操作是由CPU在指令级别上进行保证。1、引例
/**
* 验证volatile原子性
*/
public class AtomicityTest implements Runnable {
volatile int i = 0;
@Override
public void run() {
synchronized (this){
i++;
}
}
public void value() {
System.out.println("i=" + i);
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
AtomicityTest test = new AtomicityTest();
for (int j = 0; j ) {
Thread t = new Thread(test);
t.start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.value();
long end = System.currentTimeMillis();
System.out.println("共耗时:"+(end-start));
}
}/**
* Atomic原子操作类
*/
public class AtomicTest implements Runnable {
private static AtomicInteger atc = new AtomicInteger(0);
@Override
public void run() {
atc.incrementAndGet();
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
AtomicTest at = new AtomicTest();
for (int j = 0; j ) {
Thread t = new Thread(at);
t.start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("i="+atc.get());
long end = System.currentTimeMillis();
System.out.println("共耗时:"+(end-start));
}
}
AtomicInteger原子类中incrementAndGet()这个方法为什么能具有原子操作,顺着源码进去看看:
2、悲观锁和乐观锁
3、CAS
3.1 什么是CAS?
3.2 CAS目的
3.3 CAS实现原子操作的三大问题
Java中的CAS
标签:com 源码 inter dex 作用 class 标记 正是 目的
原文地址:https://www.cnblogs.com/light-sunset/p/12903127.html