可重入锁&不可重入锁

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

什么是可重入锁?

  • 同一个线程可以重入上锁的代码段,不同的线程则需要进行阻塞
  • Java的可重入锁有:ReentrantLock(显式的可重入锁)、synchronized(隐式的可重入锁)
  • 可重入锁的最大作用是避免死锁
  • 同步锁可以再次进入(同一个线程)

就比如锁方法A上锁lock而方法B也上锁lock,并且在方法A中调用方法B,不会出现死锁的情况,因为它们处于同一个线程用的是同一把锁,所以可重入锁运行再次进入。

不可重入锁

这段代码模拟了不可重入锁的构造,运行后发现出现死锁的情况这是因为在method1方法中上锁之后没有释放,在调用method2的时候内部再一次调用了lock方法,上次method1调用lock方法的时候已经将isLock = true,所以一直处于while循环当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码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后出现阻塞

可重入锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
java复制代码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是可重入锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码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是可重入锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
java复制代码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

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%