Java高并发程序设计——无锁

Java高并发程序设计——无锁

一、无锁与有锁区别?
对于并发控制而言,是一种悲观的策略。它总是假设每次的临界区的操作会产生冲突,因此,必须对每次操作都小心翼翼。如果有多个线程同时需要访问临界区资源,则宁可牺牲性能让线程进行等待,因此说锁会阻塞线程执行。而无锁是一种乐观的策略,它会假设对资源的访问是没有冲突的。既然没有冲突,自然不需要等待,所以所有的线程都可以在不停顿的状态下持续执行,如果遇到冲突怎么办?
无锁的策略使用一种叫做比较交换(CAS,Compare And Swap)的技术来鉴别线程冲突,一旦检测道到冲突产生,就重试当前操作知道没有冲突为止。

二、无锁与锁相比的优点?
虽然使用无锁会使程序看起来更复杂,但是无锁拥有锁无法比拟的优点:
1、由于其非阻塞性,它不存在死锁问题,线程间的相互影响也远远比基于锁的方式要小。
2、使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销。

三、CAS原理
CAS算法过程:它包含三个参数CAS(V,E,N),其中V表示要更新的变量E表示预期值N表示新值。仅当V值等于E值时,才会将E值设为N,如果V值和E值不同,则当前线程不做任何修改。最后,CAS返回当前V的真实值。这个过程是原子性的。
当多个线程同时使用CAS操作一个变量时,只有一个会成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,也允许失败的线程放弃操作。

四、无锁常用类
1、AtomicInteger
可以把它看成一个整数,它是可变的,且是线程安全的,对其做的任何修改都是用CAS指令进行的,以下是AtomicInteger的API:
在这里插入图片描述
2、AtomicReference
由上文知AtomicInteger是对整数的封装,而AtomicReference是对引用对象的封装,保证在修改对象引用时的线程安全性。与AtomicInteger类似。

3、AtomicStampedReference
如果对象在修改过程中丢失了状态信息,AtomicReference将无法捕捉到这一点。例如对一个整形变量修改,当其小于20时对其加上10,若A线程对其执行加10的操作,操作成功同时有一个B线程对变量进行修改使其减少10,那么A线程会误以为加10操作没有成功,可能会再次进行加10操作,这是可能导致问题的。
为解决这种状态问题,采用带有时间戳的对象引用:AtomicStampedReference。其原理为:它内部不止维护了对象值,也维护了一个时间戳(可以用任何一个整数来表示状态值),当对象数值被修改,除了更新数据本身,还要更新时间戳。然乎在设置对象值时,必须要满足对象值与时间戳值都等于期望值,才会写入成功,这样就可以防止不恰当的写入。

4、AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
以AtomicIntegerArray为例,常用API:
在这里插入图片描述
5、AtomicIntegerFieldUpdater
软件设计一条重要原则:开闭原则
什么是开闭原则
在面向对象编程中,类、函数、模块对于扩展应该是开放的,对于修改应该是封闭的。

如果由于初期考虑不周,导致后期需要对一些普通变量进行线程安全,为了保证开闭原则,我们可以采用原子包中的AtomicIntegerFieldUpdater,它可以在不改动(或者极少改动)源代码的基础上,让普通的变量也可以获得CAS操作带来的线程安全性。
根据数据类型不同,有三种Updater:
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值