多线程进阶(七)----乐观锁和悲观锁

多线程进阶(七)----乐观锁和悲观锁,第1张

多线程基础概念:多线程入门(一)
多线程基础实现:多线程入门(二)
多线程管理:多线程基础(三)
线程间的状态转换:多线程基础(四)
线程间的通信:多线程进阶(五)
锁机制:多线程进阶(六)

今天我们讲一下锁的分类,锁按照不同的角度会有不同的分类,我们就从悲观锁乐观锁的角度来解析一下:

多线程进阶(七)----乐观锁和悲观锁
  • 1、悲观锁和乐观锁
    • 1.1 悲观锁
    • 1.2 乐观锁
    • 1.3 场景
  • 2、CAS
    • 2.1 概念
    • 2.2 Java实现CAS的原理 - Unsafe类
    • 2.3 CAS实现原子 *** 作的三大问题
      • 2.3.1 ABA问题
      • 2.3.2 循环时间长开销大
      • 2.3.3 只能保证一个共享变量的原子 *** 作

1、悲观锁和乐观锁 1.1 悲观锁

对于悲观锁来说,它总是认为在每次访问系统资源时都会发生竞争,(总有刁民想害朕),所以必须每次 *** 作都会加上锁(每次出宫都必须带上御前护卫大内高手),来保证临界区的程序同一时间只有一个线程在执行(保证自己身边的同一时间只有朕一人。)。

1.2 乐观锁

乐观锁刚好与悲观锁相反,它是乐天派,总是认为每次访问系统资源没有竞争,不会发生冲突(朕是真龙天子,不会有刁民想害朕),线程可以不停的执行,无需加锁(朕的身边无需高手),⽽⼀旦多个线程发⽣冲突,乐观锁通常是使⽤⼀种称为CAS的技术来保证线程执⾏的安全性。(朕会以德服人)。

1.3 场景
  • 乐观锁多⽤于“读多写少“的环境,避免频繁加锁影响性能;
  • ⽽悲观锁多⽤于”写多读少“的环境,避免频繁失败和重试影响性能。
2、CAS 2.1 概念

CAS的全称是:⽐较并交换(Compare And Swap)。在CAS中,有这样三个值:

  • V:要更新的变量(var)
  • E:预期值(expected)
  • N:新值(new)

⽐较并交换的过程如下:
判断V是否等于E,如果等于,将V的值设置为N;
如果不等,说明已经有其它线程更新了V,则当前线程放弃更新,什么都不做。

所以这⾥的预期值E本质上指的是“旧值”。

2.2 Java实现CAS的原理 - Unsafe类

CAS是⼀种原⼦ *** 作。那么Java是怎样来使⽤CAS的呢?
在Java中,有⼀个 Unsafe 类,它在 sun.misc 包中。它⾥⾯是⼀些 native ⽅法,
其中就有⼏个关于CAS的:

boolean compareAndSwapObject(Object o, long offset,Object expected, Object x);
boolean compareAndSwapInt(Object o, long offset,int expected,int x);
boolean compareAndSwapLong(Object o, long offset,long expected,long x);
2.3 CAS实现原子 *** 作的三大问题 2.3.1 ABA问题

ABA问题就是:有一个变量,原先值为A,更新了为B,后面又更新成了A,这时候CAS是检查不出变化的,但却被更新了两次。
ABA问题的解决思路是在变量前⾯追加上版本号或者时间戳。

2.3.2 循环时间长开销大

一般情况下,CAS和自旋结合使用,如果自旋CAS长时间不成功,则会一直占有CPU大量资源;
解决思路是让JVM⽀持处理器提供的pause指令。

pause指令能让⾃旋失败时cpu睡眠⼀⼩段时间再继续⾃旋,从⽽使得读 *** 作的频
率低很多,为解决内存顺序冲突⽽导致的CPU流⽔线重排的代价也会⼩很多。

2.3.3 只能保证一个共享变量的原子 *** 作

两种解决方案:

  1. 使⽤JDK 1.5开始就提供的 AtomicReference 类保证对象之间的原⼦性,把多个
    变量放到⼀个对象⾥⾯进⾏CAS *** 作;
  2. 使⽤锁。锁内的临界区代码可以保证只有当前线程能 *** 作。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/720539.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存