Java中各种锁的介绍、锁之间的区别

公平/非公平锁 (FairSync/NotfairSync)


公平锁:按照申请锁的顺序来获取锁。
非公平锁:不是按照申请锁的顺序来获取锁。

非公平锁的优点在于吞吐量比公平锁大。

ReentrantLock可以通过构造函数来选择是公平锁or非公平锁。
Synchronized也是一种非公平锁。由于是JVM控制的,所以没有任何办法使其变成公平锁。

独占锁/共享锁 (ReadWriteLock 写入时——> 独占锁 读取时——> 共享锁)


独享锁:指某个锁一次只能被一个线程所持有。
共享锁:指某个锁可被多个线程所持有。

ReentrantLock&Synchronized&ReadWriteLock的WriteLock是独占锁。
ReadWriteLock的ReadLock是共享锁。

互斥锁/读写锁


上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。

互斥锁:实现就是ReentrantLock。
读写锁:实现就是ReadWriteLock。

乐观锁/悲观锁


乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。

乐观锁:认为对于同一个数据的并发操作,基本是不会发生修改的。效率肯定会高,实现会很复杂。实现:CAS。

悲观锁:认为不加锁的并发操作一定会出问题。实现:ReentrantLock、Synchronized等。效率低,实现简单。

自旋锁


Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。

偏向锁/轻量级锁/重量级锁


是针对Synchronized的锁的状态。在Java 5通过引入锁升级的机制来实现高效Synchronized。

偏向锁:是指一段同步代码一直被一个线程所访问,假如该锁没有被其他线程所获取,没有其他线程来竞争该锁,那么持有偏向锁的线程将永远不需要进行同步操作。降低获取锁的代价。
轻量级锁:是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁:是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

锁膨胀


当出现有两个线程来竞争锁的话,那么偏向锁就失效了,此时锁就会膨胀,升级为轻量级锁。这也是我们经常所说的锁膨胀

锁撤销


由于偏向锁失效了,那么接下来就得把该锁撤销,锁撤销的开销花费还是挺大的,其大概的过程如下:

在一个安全点停止拥有锁的线程。
遍历线程栈,如果存在锁记录的话,需要修复锁记录和Markword,使其变成无锁状态。
唤醒当前线程,将当前锁升级成轻量级锁。
所以,如果某些同步代码块大多数情况下都是有两个及以上的线程竞争的话,那么偏向锁就会是一种累赘,对于这种情况,我们可以一开始就把偏向锁这个默认功能给关闭


重入锁 (ReentrantLock)


重入锁:同一个线程,可以多次获得同一个锁,释放也是需要多次释放。

分段锁


分段锁其实是一种锁的设计思想,通过分段加锁来实现高效并发操作。实现:ConcurrentHashMap。

分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。

ConcurrentHashMap中的分段锁称为Segment, 当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片