这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
什么是可重入锁?
-
同一个线程可以重入上锁的代码段,不同的线程则需要进行阻塞
-
Java的可重入锁有:ReentrantLock(显式的可重入锁)、synchronized(隐式的可重入锁)
-
可重入锁的最大作用是避免死锁
-
同步锁可以再次进入(同一个线程)
就比如锁方法A上锁lock而方法B也上锁lock,并且在方法A中调用方法B,不会出现死锁的情况,因为它们处于同一个线程用的是同一把锁,所以可重入锁运行再次进入。
不可重入锁
这段代码模拟了不可重入锁的构造,运行后发现出现死锁的情况这是因为在method1方法中上锁之后没有释放,在调用method2的时候内部再一次调用了lock方法,上次method1调用lock方法的时候已经将isLock = true,所以一直处于while循环当中
public class NotReentrantLockDemo {
static MyLock lock = new MyLock();
public static void main(String[] args) throws InterruptedException {
new NotReentrantLockDemo().method1();
}
public void method1() throws InterruptedException {
lock.lock();
System.out.println("this is method1");
method2();
lock.unlock();
}
public void method2() throws InterruptedException {
lock.lock();
System.out.println("this is method2");
lock.unlock();
}
}
class MyLock{
private boolean isLock = false;
public synchronized void lock() throws InterruptedException {
while(isLock){
wait();
}
isLock = true;
}
public synchronized void unlock(){
isLock = false;
notify();
}
}
测试结果: 仅打印this is method1后出现阻塞
可重入锁
public class ReentrantLockDemo {
static MyReentrantLock lock = new MyReentrantLock();
public static void main(String[] args) throws InterruptedException {
new ReentrantLockDemo().method1();
}
public void method1() throws InterruptedException {
lock.lock();
System.out.println("this is method1");
method2();
lock.unlock();
}
public void method2() throws InterruptedException {
lock.lock();
System.out.println("this is method2");
lock.unlock();
}
}
class MyReentrantLock{
private boolean isLock = false;
Thread lockThread = null;
int lockCount = 0;
public synchronized void lock() throws InterruptedException {
while(isLock && Thread.currentThread()!=lockThread){
wait();
}
isLock = true;
lockCount++;
lockThread = Thread.currentThread();
}
public synchronized void unlock(){
if(lockThread == Thread.currentThread()){
lockCount --;
if(lockCount == 0){
isLock = false;
notify();
}
}
}
}
测试结果:
this is method1
this is method2
解析
可以看到与不可重入锁相比,可重入锁新增两个属性上锁的线程lockThread和上锁的次数lockCount,通过这两个变量的控制实现防止死锁的目的。
synchronized是可重入锁
public class ReentrantLockDemo {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{resource.method1();}).start();
}
}
class Resource{
public synchronized void method1(){
System.out.println("this is method1");
System.out.println(Thread.currentThread().getId());
method2();
}
public synchronized void method2(){
System.out.println("this is method2");
System.out.println(Thread.currentThread().getId());
}
}
运行结果:
this is method1
12
this is method2
12
ReentrantLock是可重入锁
public class ReentrantLockDemo {
public static void main(String[] args) throws InterruptedException {
new Thread(new Task()).start();
}
}
class Task implements Runnable {
static Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();
process1();
lock.unlock();
}
public void process1() {
System.out.println("this is process1" + "/t id=" + Thread.currentThread().getId());
process2();
}
public void process2() {
lock.lock();
System.out.println("this is process2" + "/t id=" + Thread.currentThread().getId());
lock.unlock();
}
}
this is process1/t id=13
this is process2/t id=13