多线程基础概念:多线程入门(一)
多线程基础实现:多线程入门(二)
多线程管理:多线程基础(三)
线程间的状态转换:多线程基础(四)
线程间的通信:多线程进阶(五)
锁机制:多线程进阶(六)
今天我们讲一下锁的分类,锁按照不同的角度会有不同的分类,我们就从悲观锁和乐观锁的角度来解析一下:
- 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.2 乐观锁乐观锁刚好与悲观锁相反,它是乐天派,总是认为每次访问系统资源没有竞争,不会发生冲突(朕是真龙天子,不会有刁民想害朕),线程可以不停的执行,无需加锁(朕的身边无需高手),⽽⼀旦多个线程发⽣冲突,乐观锁通常是使⽤⼀种称为CAS的技术来保证线程执⾏的安全性。(朕会以德服人)。
1.3 场景- 乐观锁多⽤于“读多写少“的环境,避免频繁加锁影响性能;
- ⽽悲观锁多⽤于”写多读少“的环境,避免频繁失败和重试影响性能。
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问题的解决思路是在变量前⾯追加上版本号或者时间戳。
一般情况下,CAS和自旋结合使用,如果自旋CAS长时间不成功,则会一直占有CPU大量资源;
解决思路是让JVM⽀持处理器提供的pause指令。
2.3.3 只能保证一个共享变量的原子 *** 作pause指令能让⾃旋失败时cpu睡眠⼀⼩段时间再继续⾃旋,从⽽使得读 *** 作的频
率低很多,为解决内存顺序冲突⽽导致的CPU流⽔线重排的代价也会⼩很多。
两种解决方案:
- 使⽤JDK 1.5开始就提供的
AtomicReference
类保证对象之间的原⼦性,把多个
变量放到⼀个对象⾥⾯进⾏CAS *** 作; - 使⽤锁。锁内的临界区代码可以保证只有当前线程能 *** 作。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)