文章目录
可重入锁 与 不可重入锁
可重入锁:
- 当线程试图获取自己 已经持有的锁时,会立刻获得这个锁,不用等待,可以理解为这个锁可以继承。
- 在锁对象的内部会维护一个 计数器,每次获取锁时,计数器 +1,释放锁时,计数器 -1,当计数器 = 0,释放锁。
- 如果没有可重入锁,当已经获取锁的线程 再次获取锁时,就会进入死锁状态。
不可重入锁:
- 与可重入锁对应,即一个线程获取到锁后,当再次获取这个锁时,需要等待这个线程释放锁之后才能获取,很明显发生了 死锁阻塞。
在 java 中,synchronized、ReentrantLock 都是可重入锁。
// 测试 synchronized 的可重入特性
public class ReentrantTest {
public static void main(String[] args) {
// 第一次获取锁
synchronized (ReentrantTest.class){
while (true){
// 尝试不断的 获取同一把锁
synchronized (ReentrantTest.class){
System.out.println("ReentrantLock");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
结果如下:
结论:当一个线程获取锁后,当再次获取同一把锁时,会默认已经获取了。
代码简单模拟
- 模拟不可重入锁
public class NotReentrantLock{
private static boolean isLock = false;
// 加锁
public synchronized void lock() throws InterruptedException {
// 判断是否加锁
while (isLock){
wait();
}
// 锁住当前线程
isLock = true;
}
// 解锁
public synchronized void unLock(){
isLock = false;
notify();
}
}
public class NotReentrantLockTest {
private static NotReentrantLock notReentrantLock = new NotReentrantLock();
public static void main(String[] args) throws InterruptedException {
notReentrantLock.lock();
dosomething();
notReentrantLock.unLock();
}
public static void dosomething() throws InterruptedException {
// 在内层方法中 再次获取锁
notReentrantLock.lock();
System.out.println("dosomething...");
notReentrantLock.unLock();
}
}
结果会被阻塞
- 模拟可重入锁
public class MyReentrantLock{
// 标识是否加锁
private boolean isLock = false;
// 锁计数器,记录加锁的次数
private int count;
// 暂存当前持有锁的线程
private Thread currLockThread;
// 加锁
public synchronized void lock() throws InterruptedException {
Thread currThread = Thread.currentThread();
// 如果在一个线程内,则不进行阻塞,即可重入
while (isLock && currLockThread != currThread){
wait();
}
// 加锁次数 ++
count++;
isLock = true;
thread = tep;
}
// 解锁
public synchronized void unLock(){
if (--count == 0) {
isLock = false;
thread = null;
notify();
}
}
// get set...
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public class MyReentrantLockTest {
private static MyReentrantLock myReentrantLock = new MyReentrantLock();
public static void main(String[] args) throws InterruptedException {
myReentrantLock.lock();
System.out.println(myReentrantLock.getCount());
dosomething();
myReentrantLock.unLock();
System.out.println(myReentrantLock.getCount());
}
public static void dosomething() throws InterruptedException {
// 在内层方法中 再次获取锁
myReentrantLock.lock();
System.out.println(myReentrantLock.getCount());
System.out.println("dosomething...");
myReentrantLock.unLock();
System.out.println(myReentrantLock.getCount());
}
}
代码执行结果如下