可重入锁vs不可重入锁
2019-06-16 本文已影响0人
归来依旧少女
一、代码展示
先设计一个不可重入锁:
public class UnreentrantLock {
private Thread localThread;
private boolean isLocked = false;
/**
* 加锁
* @throws InterruptedException
*/
public synchronized void lock() throws InterruptedException {
while(isLocked) {
System.out.println(Thread.currentThread().getName()+"没有获取到锁,等待中");
wait();
}
isLocked = true;
localThread = Thread.currentThread();
System.out.println(localThread.getName()+"获取到锁");
}
/**
* 解锁
*/
public void unlock() {
if(isLocked) {
System.out.println(Thread.currentThread().getName()+"释放锁");
isLocked = false;
localThread = null;
}
}
}
测试:
public class Count {
private UnreentrantLock lock = new UnreentrantLock();
public void print() {
try {
lock.lock();
System.out.println("print start..");
//调用add()方法
add();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void add() {
try {
lock.lock();
System.out.println("add...");
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Count count = new Count();
count.print();
}
}
运行结果:
main获取到锁
print start..
main没有获取到锁,等待中
可以看到同一个线程,重复获取锁失败,形成死锁,这就是不可重入锁。
然后再写一个可重入锁:
public class ReentrantLock {
private Thread localThread = null;
private boolean isLocked = false;
private int lockedCount = 0;
/**
* 加锁
*
* @throws InterruptedException
*/
public synchronized void lock() throws InterruptedException {
Thread thread = Thread.currentThread();
while (isLocked && localThread != thread) {
System.out.println(Thread.currentThread().getName() + "没有获取到锁,等待中");
wait();
}
isLocked = true;
localThread = thread;
lockedCount++;
System.out.println(localThread.getName() + "获取到锁");
}
/**
* 解锁
*/
public void unlock() {
if (isLocked) {
System.out.println(Thread.currentThread().getName() + "释放锁");
lockedCount--;
if (lockedCount == 0) {
isLocked = false;
localThread = null;
}
}
}
}
测试:
private ReentrantLock lock = new ReentrantLock();
运行结果:
main获取到锁
print start..
main获取到锁
add...
main释放锁
main释放锁
可以看到,同一个线程可以多次获取锁。
二、总结
可重入锁又称之为递归锁,就是一个线程在外层方法获取到锁,在内层方法自动获取到锁,而不会因为没有获取到锁而阻塞。java中的ReentrantLock和synchronized都是可重入锁。可重入锁可一定程度上减少死锁,而不可重入锁则再容易发生死锁。