多线程-day-09CAS原理

目录

原子操作CAS

什么是原子操作?如何实现原子操作?

CAS的原理

CAS的问题

JDK中相关原子操作类的使用


        在JDK5之前,Java语言同步操作,需要依赖synchronized关键字进行同步。这里就产生了锁的概念。synchronized称之为内置锁,也可以称为互斥锁。synchronized内置锁(互斥锁)可能带来以下几个问题:

  1. 虽然是线程安全,但是在多个线程竞争的情况下,有些一些优先级较低的线程获得锁,那么优先级较高的线程将被阻塞,优先级倒置,优先级高的线程一直等待锁被释放。会引起性能风险。
  2. 多个线程竞争情况下,频繁的加锁、释放锁,会导致较多的上下文切换和调度演示,因而对性能造成影响。

        考虑使用volatile关键字,但是volatile不能保证操作的原子性,因此对于同步的操作最终还是要回到锁的机制上。

        独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其他所有需要锁的线程挂起,一直等待持有锁的线程释放锁后再进行调度。另外一种锁就是乐观锁乐观锁的机制就是:每次不加锁,而是假设没有冲突就去完成某项操作,如果产生冲突失败就重试,一直到成功为止

CAS的原理

        利用现代处理器都支持CAS指令,循环这个指令,直到成功为止。 从某种程度上,CAS就是乐观锁。

        CAS(Compare And Swap),指令级别保证这是一个原子操作。

        CAS三个运算符:一个内存地址V,一个期望值A,一个新值B。

        基本思路:如果地址V上的值,和期望值A相等,则给地址V赋给新值B。如果不是,则不做操作,在循环内(死循环/自旋)不断进行CAS操作,直到成功。

CAS带来的问题

        ABA问题:比如两个线程T1和T2,当线程T1从内存地址V取的值A,此时T2也从内存地址V取的值A,并且T2进行了一些运算或者操作,将值A变成了值B,然后T2又因为某种操作将值B变回了值A;此时T1进行CAS操作的时候,发现内存V的值还是只A,然后也操作成功了。这里虽然线程T1执行了操作,并且最终的值也没有问题,但是很明显,对于操作这个内存V的值A,是已经由线程T2进行了相关操作后返回的值,因此就产生了ABA的问题。

        举个简单例子:两个人张三,李四;张三把一个打满水的杯子放在桌子上,然后去做其他事情去了;李四经过然后拿起杯子喝了半杯,然后再把杯子的水打满。张三来了之后,并没有杯子有什么异常,看起来还是之前的那杯水,但是实际上杯子里面的水已经动过了。有谁希望自己的杯子被其他人动过呢~

        ABA问题解决方案:设置一个版本号,如果某个线程对值进行了操作,则操作完后加一个版本号进行区分。例如:值A初始版本号为1,那么经过T2变化的过程为:A1--->B2--->A3,通过版本号,线程T1就知道值A已经经过了改变。这也是乐观锁的操作流程。

        也就是张三把杯子放在桌子上,然后放一个纸条在桌子上,如果谁要动杯子,先在纸上进行一个记录,这样张三做完其他事情回来之后,也可以看到是否自己的杯子是否被动过了。

        开销问题:因为CAS操作,都是在一个循环内(死循环/自旋)进行操作,如果长时间不成功则一直进行CAS原子操作,因此会给CPU带来非常大的开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

        只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作。

Jdk中相关原子操作类的使用

  1. 更新基本类型类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
  2. 更新数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
  3. 更新引用类型:AtomicReference,AtomicMarkableReference,AtomicStampedReference
  4. 原子更新字段类: AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater

以上为CAS原子操作的相关概念,以及和synchronized内置锁的相关区别,重点在于理解CAS原子操作的原理,为什么使用CAS原子操作,CAS原子操作会产生哪些问题。JDK中提供了哪些CAS原子操作类的使用。

 

 

更多精彩敬请关注公众号

Java极客思维

微信扫一扫,关注公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值