什么是可重入锁和不可重入锁?
首先我们从字面意思理解
** 不可重入锁**,要理解可重入锁,我就想是不是有不可重入锁,果然还真有,从字面上理解就是:不可以重新进入锁,资料上的解释就是同一个线程不能够重新获取同一个锁,这似乎也符合我们初步学习锁时的理解,lock()后只有unlock()后其他地方才能调用lock()成功。
按照我们对锁的理解,第n行代码处调用了lock.lock() 方法,其他地方尝试调用lock.lock()都会被阻塞,等待第n行代码的锁被释放
出现的问题
就像下面的代码,如果使用不可重入锁就导致了死锁状态。
第一行获取锁,第三行这一行会等待第一行的锁释放锁,才能获取成功,第一行的锁要运行到第六行才能释放,互相等待,就产生了死锁
lock.lock();//第一行获取锁
{
lock.lock();//第三行,这一行会等待上一行的锁释放锁,才能获取成功,第一行的锁要运行到第六行才能释放
lock.unlock();//第四行,释放第三行锁
}//这是一个代码块,一般是调用别人的方法,我们不能确定别人的方法中有没有申请这个锁
lock.unlock();//第六行,释放第一行锁
引入可重入锁
** 可重入锁** ,即可以重新进入锁,就是我们获取这一把锁之后,同一个线程尝试获取锁时,可以获取锁成功,这就是可重入锁。
就像下面的代码,如果使用可重入锁就不会出现死锁状态。
第一行获取锁,第三行这一行会判断是同一个线程,同样也可以获取锁,不会等待第一行锁释放,执行成功继续往下执行
lock.lock();//第一行获取锁
{
lock.lock();//第三行,这一行会判断是同一个线程,同样也可以获取锁,不会等待第一行锁释放
lock.unlock();//第四行,释放第三行锁
}//这是一个代码块,一般是调用别人的方法,我们不能确定别人的方法中有没有申请这个锁
lock.unlock();//第六行,释放第一行锁
Java中几乎所有自带的的锁实现几乎都是可重入锁,当然我们常见的ReentrantLock 和 synchronize就是典型的可重入锁。
实现思路和DEMO代码
不可重入锁
这里只是demo代码,没有实现太多具体细节,成员变量一个isLocked 存储锁状态,lockedBy 存储获取锁的线程用于解锁时使用
/**
* 不可重入锁
*
*/
public static class UnReLock {
private volatile boolean isLocked = false;
Thread lockedBy = null; //记录当前获取锁线程
public synchronized void lock() throws InterruptedException {
Thread thread = Thread.currentThread();
while (isLocked) {
wait();
}
isLocked = true;
lockedBy = thread;
}
public synchronized void unlock() {
if (Thread.currentThread() == this.lockedBy) {
isLocked = false;
lockedBy = null;
notify();
}
}
}
可重入锁
首先可重入锁的可重入指的是同一个线程,所以我们需要判断是否是同一个线程尝试获取锁;
其次我们知道可以多次获取锁,不可能unlock()一次就把锁给释放了,所以我们对取锁次数进行计数,当调用lock()时锁计数+1,释放锁时就-1,这样当锁数量为0时就说明所有获取的锁都被释放。
实现代码如下(这里只是demo示例代码,演示思路,没有实现太多具体细节)
/**
* 可重入锁
* @author chenlinhui
*
*/
public static class ReLock {
volatile boolean isLocked = false; //记录锁状态
volatile Thread lockedBy = null; //记录当前获取锁线程
volatile int lockedCount = 0; //记录计数器
public synchronized void lock() throws InterruptedException {
Thread thread = Thread.currentThread();
while (isLocked &&( lockedBy != thread)) {
//已加锁,且不是同一个线程,需要等待
wait();
}
isLocked = true;
lockedCount++;//锁次数+1
lockedBy = thread;
}
public synchronized void unlock() {
if (Thread.currentThread() == this.lockedBy) {
lockedCount--;//锁次数减一
if (lockedCount == 0) { //锁次数为0,说明所有锁被释放
isLocked = false;
lockedBy = null;
notify();
}
}
}
}
验证
public class TestUnReLock {
static ReLock lockObject = new ReLock(); //测试可重入锁
//static UnReLock lockObject = new UnReLock(); //打开注解测试不可重入锁
/**
*我们自己写的方法
*/
public static void methodA_1() throws InterruptedException {
lockObject .lock();
System.out.println("methodA_1,获取锁。。。。");
methodB_1();//调用别人实现的方法
lockObject.unlock();
System.out.println("methodA_1,释放锁成功了");
}
/**
*可能是别人的不可修改的接口或方法
*/
public static void methodB_1() throws InterruptedException {
System.out.println("methodB_1,等待锁。。。。");
lockObject .lock();
System.out.println("methodB_1,我获取锁成功了");
lockObject .unlock();
System.out.println("methodB_1,释放锁成功了");
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InterruptedException {
methodA_1();
}
可重入锁结果,执行成功
methodA_1,获取锁。。。。
methodB_1,等待锁。。。。
methodB_1,我获取锁成功了
methodB_1,释放锁成功了
methodA_1,释放锁成功了
不可重入锁结果:无限等待
methodA_1,获取锁。。。。
methodB_1,等待锁。。。。