java并发编程(3)-----原子变量与非阻塞同步机制

一、锁的缺点

优先级反转:即锁被低优先级线程占据,即便高优先级的线程可以抢占cpu,也会因为获取不到锁,而被阻塞,使得高优先级的线程优先级实际上比低优先级的低。

而且如果每个线程持有锁的时间很短,其他线程阻塞后被唤醒的开销很大。

二、CAS

CAS:比较并交换,包含3个操作数,需要读写的内存位置V、进行比较的值A和需要写入的新值B,当且仅当V=A的时候,B才会以原子操作的方式更换V的值,否则不执行任何操作,而且无论是否成功,都返回V的值。

CAS的含义:我认为V的值应该是A,如果你持有的是A,那么说明你持有的是V的最新版本的值,可以让你更新V的值。如果不是,说明你持有的V的值是无效的,不允许你更改。

CAS是一种乐观的并发机制,即乐观锁,竞争失败的线程是不会挂起的,而是可以再次尝试,当然,当重试一定次数后,可以将其挂起。(可能每个系统实现的不一样,CAS的具体失败策略就不一样)

CAS的使用流程:首先从V处读取值A,然后将A更新为B,再通过CAS原子操作将V的值变为B,只要在CAS执行之前,没有别的线程提前将V的值改为别的,则V的值就能成功更新为B。如果V的值不是A了,说明该线程执行期间已经有别的线程提前更改过V的值了,需要重试或者放弃操作。

CAS的主要缺点是需要调用者处理竞争问题(重试、回退、放弃),而使用锁则是由系统来帮我们处理竞争问题(挂起、阻塞等),同时还会存在ABA的问题。

ABA问题: CAS存在ABA问题,ABA问题是指假设线程1中的旧值A为1,新值B为3,线程1还未执行CAS操作更改,线程2来对该数据进行更改,将数据先改为2,又改回了1(即线程2进行了2次CAS更改),这时候线程1进行CAS判断的时候,是无法知道线程2对该数据进行过更改的。即数据从1->2->1的这个过程是无法被发现的。

  • 如果是基础类型,无所谓,不影响结果。
  • 如果是引用类型,可能会造成一些状态不一致。因为,如果是引用类型,只能保证引用不变,但是引用指向的对象可能发生了一些变化。

假设用链表实现一个栈,初始化向栈中压入B、A两个元素,栈顶head指向A元素。在某个时刻,线程1试图将栈顶换成B,但它获取栈顶的oldValue(为A)后,被线程2中断了(此时还未进行CAS操作,只是获取OldValue,CAS操作是原子操作)。线程2依次将A、B弹出,然后压入C、D、A。然后换线程1继续运行,线程1执行compareAndSet发现head指向的元素确实与oldValue一致,所以就将head指向B。但是,注意标黄的语句,线程2在弹出B的时候,将B的next置为null了。因此在线程1将head指向B后,链表中只剩下了一个孤零零的元素B,但按照预期,链表元素中应该放的是B->A->D->C

ABA问题可以通过版本号机制来解决这个问题。

三、原子变量类

原子变量将发生竞争的范围缩小到某个变量上。原子操作都是基于CAS实现的。原子变量可以分为4类:标量类、更新器类、数组类以及复合变量类。

标量类最常用,包含:AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference。

原子数组类对数组元素都具有volatile类型的访问语义(即数组中每个元素都相当于被volatile关键字标记了),而用volatile关键字定义的数组,仅对数组的引用拥有volatile语义,而数组中的元素则没有。

锁和原子变量适用于不同竞争程度,中低程度的竞争下,原子变量能提供更高的可伸缩性,在高强度竞争下,锁能更有效的避免竞争。

四、非阻塞算法

基于锁的算法中可能会发生各种活跃性故障,如果线程在持有锁时由于阻塞I/O、内存缺页或者其它延迟等导致推迟执行时,那么其他需要该锁的线程也都不能继续执行下去。

如果某种算法,一个线程的失败或挂起不会导致其他线程也失败或挂起,那么就是非阻塞算法。

如果某种算法,在算法的每个步骤都存在某个线程可以执行下去,那么就是无锁算法。

如果某种算法,仅通过CAS用于协调线程之间的操作,并且可以正确运行,那么就是一种无锁的非阻塞算法。如果有多个线程竞争一个CAS,总会有一个线程胜出并执行下去,所以在非阻塞算法中一般不会出现死锁和优先级反转问题,但可能出现饥饿和活锁问题。

其他非阻塞实现除了CAS还有关联存储(Load-Linked)、条件存储(Store-Conditional)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值