Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁

时间:2022-03-30 20:04:27

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();
}

}

运行代码会发现出现死锁

Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁

可重入锁:

// 可重入锁
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());
}
}

运行代码:

Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁

可重入锁通过计数方式,没有出现死锁现象。