一、可重入锁原理?
可重入锁最重要的作用就是可以避免死锁。防止出现线程被自己所阻塞的情况。
比如:线程A获取了对象B的锁,开始执行代码,然后又发现下面的一个方法需要再次获取对象B的锁,此时对象B的锁已经被线程A占用了。
- 不过只要另外一个线程和线程A来自同一个线程,那么该线程也能获取对象B的锁。
- 目前JAVA中几乎所有的锁都是可重入锁。比如:ReentrantLock、ReentranReadWriteLock。
ReentrantLock源码分析参考博文:https://blog.csdn.net/Saintmm/article/details/124346628
ReentranReadWriteLock源码分析参考博文:[https://blog.csdn.net/Saintmm/article/details/124347762][https_blog.csdn.net_Saintmm_article_details_124347762]
可重入锁它是一个概念,在大部分时候可重入锁并不直接表示ReentrantLock,而是强调一种锁的类型。
- Synchronized也是可重入锁、非公平锁。
- 自旋锁也是可重入锁。(自旋锁由于第一次unlock()操作没有释放锁出现死锁时不叫可重入锁)
实现原理?
每一个锁对象都会关联的一个线程持有者和计数器。
- 计数器为0的时候表示锁没有被获取;
- 当用一个线程获取锁时,计数器为1,锁的线程持有者为当前线程;
- 当前再次获取锁的时候计数器+1;
- 解锁时计数器-1;计数器为0时,表示锁被释放了。
二、手写一个可重入锁
可重入锁可以避免死锁:
- 一个主线程中包含两个同步方法,线程可以多次执行这两个方法
public class ReentrantLockTest1 implements Lock {
//锁标志
private boolean isLocked = false;
//定义同一线程获取锁的次数
int lockCount = 0;
//定义一个线程
Thread thread = null;
@Override
public synchronized void lock() {
Thread currentThread = Thread.currentThread();
//如果不是第一个进来,则等待
while(isLocked && currentThread != thread){
try {
wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
//如果是第一个进来,将锁标志设为true即该线程拥有锁。
isLocked = true;
//将thread指向当前线程
thread = currentThread;
//计数器自增
lockCount++;
}
@Override
public synchronized void unlock() {
//如果当前线程是thread
if(thread == Thread.currentThread()){
lockCount--;
if(lockCount == 0){
notify();
//释放锁
isLocked = false;
}
}
}
}