cas产生:在修饰共享变量的时候经常使用volatile关键字,但是volatile值有可见性和禁止指令重拍(有序性),无法保证原子性。虽然在单线程中没有问题,但是多线程就会出现各种问题,造成现场不安全的现象。所以jdk1.5后产生了cas利用cpu原语(不可分割,连续不中断)保证现场操作原子性。
cas应用:在jdk1.5 中新增java.util.concurrent(juc)就是建立在cas之上的。相对于对于synchronized这种锁机制,cas是非阻塞算法的一种常见实现。所以juc在性能上有了很大的提升。
比如atomicinteger类,atomicinteger是线程安全的的,下面是源码
进入unsafe看到do while自循环,这里的自循环,就是在 判断预期原值 如果与原来的值不符合,会再循环取原值,再走cas流程,直到能够把新值赋值成功。
cas优点cas是一种乐观锁的思想,而且是一种非阻塞的轻量级的乐观锁,非阻塞式是指一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法。
cas 缺点循环时间长开销大,占用cpu资源。如果自旋锁长时间不成功,会给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操作。
aba问题
解决aba问题(如果值考虑收尾,不考虑过程可以忽略改问题)
添加版本号
atomicstampedreference
从java1.5开始jdk的atomic包里提供了一个类atomicstampedreference来解决aba问题。这个类的compareandset方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如 全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
cas使用的时机线程数较少、等待时间短可以采用自旋锁进行cas尝试拿锁,较于synchronized高效。
线程数较大、等待时间长,不建议使用自旋锁,占用cpu较高
以上就是java的cas怎么应用的详细内容。