JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计数值等于0时,锁释放。如果没有可重入锁的支持,在第二次 企图获得锁时将会进入死锁状态。
现实中,我们一般不会去手动实现锁,而是直接使用JDK或其他框架提供的锁,手动实现主要为了理解。
不可重入锁:
// 不可重入锁
class Lock{
// 是否占用
private boolean isLocked = false;
// 使用锁
public synchronized void lock() throws InterruptedException {
while(isLocked) {
wait();
}
isLocked = true;
}
// 释放锁
public synchronized void unlock(){
isLocked = false;
this.notify();
}
}
测试:
public class LockTest {
Lock lock = new Lock();
public void a() throws InterruptedException {
lock.lock();
b();
lock.unlock();
}
public void b() throws InterruptedException {
lock.lock();
// …业务代码
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
LockTest test = new LockTest();
test.a();
}
}
运行代码会发现出现死锁
可重入锁:
// 可重入锁
class ReLock{
// 是否占用
private boolean isLocked = false;
// 存储线程
private Thread lockedBy = null;
// 计数
private int holdCount = 0;
// 使用锁
public synchronized void lock() throws InterruptedException {
Thread t = Thread.currentThread();
while(isLocked && lockedBy != t) {
this.wait();
}
isLocked = true;
lockedBy = t;
holdCount++;
}
// 释放锁
public synchronized void unlock() {
if(Thread.currentThread() == lockedBy) {
holdCount--;
if(holdCount == 0) {
isLocked = false;
this.notify();
lockedBy = null;
}
}
}
public int getHoldCount() {
return holdCount;
}
}
测试:
public class LockTest02 {
ReLock lock = new ReLock();
public void a() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
b();
lock.unlock();
System.out.println(lock.getHoldCount());
}
public void b() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
// .....业务代码
lock.unlock();
System.out.println(lock.getHoldCount());
}
public static void main(String[] args) throws InterruptedException {
LockTest02 test = new LockTest02();
test.a();
Thread.sleep(1000);
System.out.println(test.lock.getHoldCount());
}
}
运行代码:
可重入锁通过计数方式,没有出现死锁现象。