首页 > 编程知识 正文

cas锁底层原理,悲观锁容易死锁

时间:2023-05-05 16:22:47 阅读:129224 作者:2091

1.Java合并采购订单(java.util.concurrent )的主要实现机制:

使用Volatile确保内存可见性;

采用CAS(compareandswap )算法保证数据原子性。

2 .乐观锁定(CAS算法)和悲观锁定(synchronized ) :

同步是悲观的锁。 因为总是假设最坏的情况,所以每次去取数据的时候都觉得别人会修理,所以每次都会锁上,效率很低。

乐观锁定其实是一种思想,具体包括冲突检测和数据更新两个步骤。 因此,不针对每次访问进行锁定控制,而是仅在进行更新操作时进行冲突检测和数据更新,适用于读取操作较多的程序,因此吞吐量大幅提高。 其实现方式典型的是CAS算法。 如果多个线程同时更新同一变量,则只有一个线程修改成功,其他线程失败。 更新失败的线程不会挂起,而是会被告知在这次竞争中失败,可以再次尝试。

3 .比较软件(cas )原理:

也就是说,比较和交换是著名的无锁算法。 无锁定编程是指在不使用锁定的情况下实现多线程之间的变量同步,也就是说,在线程未被阻塞的状态下实现变量同步,因此无阻塞同步(Non-blocking Synchronization ) 。

CAS算法首先包括三个操作数。

内存值(v ) -首次读取内存中的值;

估计值(a ) -重新读取的存储器中的值;

更新值(b ) -新值;

每次进行更新操作时,V==A (存储器值和预期值相等时),之后的V=B (存储器值更新为b ),否则什么也不做)比较和置换为原子操作)。 通常是旋转操作,也就是不断地重试。

//CAS算法模拟: publicclasstestcas { publicstaticvoidmain (string [ ] args ) ) CAS=newCAS ) 10 ); for(intI=0; i 10; I ) { new Thread ()-)/10线程都执行数据更新操作的int expectedValue=cas.getValue ); //在更新前获得期望值booleanb=cas.compare test (expected value,(int ) Math.random ) ); 系统. out.println (b ); ().start ); } }}class Cas{ /* *内存值; 预期值; 新值。 * */int值; //内存值publicsynchronizedintgetvalue ({返回值; }公共cas (intvalue ) (/构建方法this.value=value; //比较交换,将内存值转换为publicintcompareswap (intexpectedvalue,int newValue ) { int oldValue=value; //获取内存值if (old value==expected value ) { value=newValue; }返回old value; //publicbooleancomparetest (intexpectedvalue,int newValue ) ) { boolean flag=false; if(expectedvalue==compareswap ) expectedvalue,newValue )//确定期望值和内存值是否相等-更新是否成功flag=true; }返回标志; )4.乐观锁定的缺点

4.1 ABA问题是乐观锁定的常见问题

如果第一次读取一个变量v时检查为a值,并且在准备赋值时仍然为a值,是否可以说明其他线程没有更改该值? 显然不可能。 在此期间,CAS操作可能会被更改为其他值,然后更改为a,因此您会误以为CAS操作从来没有更改过。 这个问题被称为CAS操作的“ABA”问题。

解决方法1:在修改值的同时增加一个时间戳,只有当预期值和时间戳都相同时才进行修改。

解决方法2:JDK 1.5或更高版本的AtomicStampedReference类提供此功能。 其中的compareAndSet方法首先检查当前引用是否等于预期引用,以及当前标志是否等于预期标志,如果全部相等,则在原子上设置引用和标志值

为给定的更新值。

4.2 循环时间长开销大

自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。

4.3 只能保证一个共享变量的原子操作

CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5开始,提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来操作。

4.4 CAS与synchronized的使用情景

简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)

对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。
对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。

补充:

Java并发编程这个领域中synchronized关键字一直都是元老级的角色,很久之前很多人都会称它为 “重量级锁” 。但是,在JavaSE 1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的 偏向锁 和 轻量级锁 以及其它各种优化之后变得在某些情况下并不是那么重了。synchronized的底层实现主要依靠 Lock-Free 的队列,基本思路是 自旋后阻塞,**竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。**在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。