java并发编程:CAS、Unsafe类、重排序、伪共享

1 Q:什么是悲观锁、乐观锁

悲观锁:指在更新数据时,数据被外界修改,持保守态度。认为在更新数据的时候,大概率会有其他线程争抢共享资源。此时为了避免出错,第一个拿到资源的线程会对资源进行加排它锁, 其他没争夺到资源的线程只能进入阻塞队列 。之前上面提到的synchronized就是悲观锁的一种实现方式。

乐观锁:在更新数据时,认为数据被外界修改的概率是很小的,在更新数据时,不会对共享数据加锁,但是在正式更新数据之前会检查数据是否被其他线程修改过, 如果未被其他线程改变过就将共享变量更新成最新值,如果发现共享变量已经被其他线程更新过了,就重试,直到成功为止。典型的实现方式是CAS机制。

2 Q:那CAS机制是什么

Compare and Swap,比较并交换。如同上面提到的乐观锁,CAS是乐观锁的实现,在写回内存的时候,首先比较内存中的值与预期值是否相同,相同才会写回。

例如:假设内存中的值是x,线程中的缓存备份(预期值)A,计算后将要写回内存的值B。将B写回内存时,首先将内存中的x与预期值A比较,如果相同的话,将B赋值给x。如果不相同,认为x此时已经被其他线程修改了,重新将x赋值给A,并重新计算B,重复比较

之前,我们提到了,使用锁会阻塞线程,会带来线程上下文的切换和重新调度开销;而volatile关键字解决了共享内存的可见性,但是不解决原子性问题。CAS的出现,解决了阻塞和非原子性的问题。

在JDK的Unsafe类提供了一系列compareAndSwap*方法,是JDK提供的非阻塞原子性操作,通过硬件保证了比较–更新操作的原子性。

例子:boolean compareAndSwapLong(Object Obj, long valueOffset, long except, long update)。

​ 操作数分别对应:对象内存位置,对象中的变量的偏移量,变量预期值和新的值。 操作含义:如果对象Obj中的内存偏移量为valueOffset的变量值为except,则使用新值update替换旧值except。这是处理器提供的一个原子指令。

3 Q:CAS是完美的吗(ABA问题)

从辩证法角度讲,肯定不是;实际上,也有一个很经典的ABA问题。

1 当一个线程①,使用CAS操作,尝试将初始值为A的共享变量修改为B。假设在执行CAS操作前,另一个线程②使用CAS操作将A修改了B,然后又将B修改为了A,此时线程①再继续操作CAS,因为内存中和线程中都是A,所以操作成功 ,但是此时的A,已经不是线程①获得的A了。

其核心问题就在于,通过值判断版本变化,如果出现环形转换,(A->B->A),CAS操作是无感的。

在JDK中的AtomicStampedReference类,给每一个变量的状态值都配备了一个时间戳,从而避免了ABA问题。

2 在线程之间竞争程度大的时候,如果使用CAS,每次都有很多的线程在竞争,也就是说CAS机制不能更新成功。这种情况下CAS机制会一直重试,这样就会比较耗费CPU。 在并发量非常高的环境中,如果仍然想

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值