Java可重入锁(递归锁)
可重入锁指的是同一个线程,在外层方法获取锁后, 再进入内层方法会自动获取锁(前提,锁的是同一个对象),不会因为之前获取过没有释放导致阻塞。
Java的synchronized和ReentrantLock都是可重入锁。
可重入锁的种类
1.隐式锁(synchronized)
同步代码块-代码示例:
package multiThreads;
public class Test18 {
public static void main(String[] args) {
Object object = new Object();
new Thread(() -> {
synchronized (object) {
System.out.println("外层代码");
synchronized (object) {
System.out.println("中层代码");
synchronized (object) {
System.out.println("内层代码");
}
}
}
}).start();
}
}
运行结果:
可以看到synchronized锁定的三个代码块都执行了。
同步方法-代码示例
package multiThreads;
public class Test19 {
public static void main(String[] args) {
Test19 test19 = new Test19();
test19.m1();
}
private synchronized void m1() {
System.out.println("m1--------");
m2();
}
private synchronized void m2() {
System.out.println("m2--------");
m3();
}
private synchronized void m3() {
System.out.println("m3--------");
}
}
运行结果如下:
2.显示锁(ReentrantLock)
ReentrantLock代码示例如下:
package multiThreads;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test18 {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
//同一个线程
new Thread(() -> {
lock.lock();
try {
System.out.println("外层代码--");
lock.lock();
try {
System.out.println("中层代码--");
lock.lock();
try {
System.out.println("内层代码--");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
}
}
运行结果:
ReentrantLock的加锁解析:
第一次执行lock()方法前,reentrantLock中的sync属性值如下:
其中sync是一个ReentrantLock.NonfairSync实例,state=0代表此锁还未被获取,也即此锁还未被锁定。当执行lock.lock()方法的时候,进行如下操作:
如果锁当前未被获取,则将state从0设置为1,且将exclusiveOwnerThread设置为当前线程。如果当前锁已被获取,则尝试获取锁,具体代码如下:
通过上面的代码可以看出,当state=0的时候表示锁未被获取,当state大于0的时候表示锁已经被获取,且state值等于锁的重入次数。exclusiveOwnerThread表示锁的当前持有线程。
!!!使用显示锁ReentrantLock的时候,获取锁后一定要记得释放锁,否则可能导致后续线程无法获取此锁。