锁机制
一、介绍
锁机制是用来实现线程间同步的基础,并非是JAVA中独有的概念。本篇主要讲JAVA中的锁,按照锁分类,有以下几种锁
- 公平锁/非公平锁
- 可重入锁/不可重入锁
- 独占锁/共享锁
- 互斥锁/读写锁
- 乐观锁/悲观锁
- 分段锁
- 偏向锁/轻量级锁/重量级锁
- 自旋锁
但这些锁并不完全指的是锁,有的是锁设计,有的是锁状态,也有的是锁的特性。
下面就介绍一下关于这些锁
二、公平锁/非公平锁
1. 公平锁
就是指当多个线程都要申请锁时,需要按照申请锁的先后顺序来进行获取。
2. 非公平锁
指当多个线程申请锁时,无法确定哪一个线程会获取锁,与申请的先后顺序无关
💡 非公平锁相较于公平锁,吞吐量上会更具优势。JAVA中的synchronized关键字和ReentrantLock都是非公平锁,但ReentrantLock是通过AQS实现的线程调度,所以可以**使ReentrantLock变为公平锁;**synchronized则没有办法变为公平锁。
三、可重入锁/不可重入锁
1. 可重入锁
顾名思义就是说可以重复获取的锁,但仅仅针对同一个的线程。对于同一个线程来说,如果该对象已经获取到了该锁并且没有释放,那么它可以继续获取该锁而不会造成死锁。
2. 不可重入锁
与可重入锁相反,即使是同一个线程,在持有锁的状态下继续申请该锁,也同样造成死锁的问题。也就是说这种锁不可以递归调用,一旦递归调用就会造成死锁。
💡 ReentrantLock翻译过来就是可重入锁,所以听名字就知道他是可重入的,而synchronized实际上也是一个可重入锁
如何判断一个锁是否使可重入锁呢?
class Test{
public void a(){
ReentrantLock lock = new ReentrantLock(true);
lock.lock();
// 重复调用锁不会造成死锁即是不可重入锁
lock.lock();
}
}
四、独占锁/共享锁
1. 独占锁
在同一时间只有一个线程可以获取到这个锁,也就是说不会存在两个线程同时持有一把锁的情况,当一个线程获取到锁,其他线程就会阻塞。
2. 共享锁
允许有多个线程同时获取到该锁,不同线程获取同一把锁时不会阻塞。
五、互斥锁/读写锁
1. 互斥锁
互斥锁的效果和概念类似于独占锁,都是在同一时刻只能有一个线程获取到锁。(我不太清楚互斥锁和独占锁之间是否有区别,有知道的朋友可以留言告诉我一下。)
2. 读写锁
读写锁就是一种互斥锁。我们知道多线程读文件不会导致并发问题,但多线程写就存在并发问题。所以在读-读的场景下是不存在互斥关系的,但在读-写,写-写的场景下是存在互斥关系的,当一个线程持有了写锁,那么其他任何线程都不能获取读锁或者写锁。
💡 读写锁是一种特殊的独占锁,因为读-读的场景下并不存在互斥关系,而读-写,写-写的场景下存在互斥关系,所以读写锁更适用于读多写少的场景。
六、乐观锁/悲观锁
1. 乐观锁
乐观锁实际上并不是锁,他总是乐观的认为在他要修改数据的时候,其他线程不会进行修改。仅仅只是在更新数据的时候判断数据是否被更改。我们一般使用CAS算法+版本号进行实现。
💡