前言
之前面试的时候被问到死锁这块的问题,借着最近学习jvm来总结下死锁相关的知识。如果有地方写的不到位的地方,麻烦读者及时提出,放在评论区,我这边也好及时改正。
回顾
所谓,温故而知新,首先回顾下,我们之前学过的线程的状态以及死锁产生的条件。
线程的状态在Java中线程的状态一共被分成6种:
<ignore_js_op>
初始态(NEW)
创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态。
运行态(RUNNABLE),在Java中,运行态包括 就绪态 和 运行态。
就绪态
该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运 行。 所有就绪态的线程存放在就绪队列中。
运行态
获得CPU执行权,正在执行的线程。
由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一条 运行态的线程。
阻塞态(BLOCKED)
当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。
而在Java中,阻塞态专指请求锁失败时进入的状态。
由一个阻塞队列存放所有阻塞态的线程。
处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执 行。
等待态(WAITING)
当前线程中调用wait、join、park函数时,当前线程就会进入等待态。
也有一个等待队列存放所有等待态的线程。
线程处于等待态表示它需要等待其他线程的指示才能继续运行。
进入等待态的线程会释放CPU执行权,并释放资源(如:锁)
超时等待态(TIMED_WAITING)
当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就 会进入该状态;
它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后需要其 他线程唤醒;
进入该状态后释放CPU执行权 和 占有的资源。
与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁。
终止态(TERMINATED)
线程执行结束后的状态。
死锁产生的条件
互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链死锁问题
构造死锁
编写代码,启动2个线程,Thread1拿到了obj1锁,准备去拿obj2锁时,obj2已经被 Thread2锁定,所以发送了死锁。
01
02
03
04
05
06
07
08
09
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
40
41
42
43
44
45
46
47
48
49
50
51
|
public class TestDeadLock { private static Object obj1 = new Object(); private static Object obj2 = new Object(); public static void main(String[] args) { new Thread( new Thread1()).start(); new Thread( new Thread2()).start(); } private static class Thread1 implements Runnable { @Override public void run() { synchronized (obj1) { System.out.println( "Thread1 拿到 obj1 的锁" ); try { //停顿2秒的意义在于,让thread2线程拿到obj2的锁 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { System.out.println( "Thread1 拿到 obj2 的锁" ); } } } } private static class Thread2 implements Runnable { @Override public void run() { synchronized (obj2) { System.out.println( "Thread2 拿到 obj2 的锁" ); try { //停顿2秒的意义在于,让thread1线程拿到obj1的锁 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj1) { System.out.println( "Thread2 拿到 obj1 的锁" ); } } } } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
[root @localhost test]# javac TestDeadLock.java [root @localhost test]# ll total 27692 drwxr-xr-x. 9 root root 220 Jan 3 23 : 22 apache-tomcat- 7.0 . 99 -rw-r--r--. 1 root root 9587605 Dec 11 21 : 44 apache-tomcat- 7.0 . 99 .tar.gz -rw-------. 1 root root 18737999 Jan 4 16 : 52 dump.dat -rw-r--r--. 1 root root 433 Jan 3 23 : 23 Main. class -rw-r--r--. 1 root root 135 Jan 3 23 : 23 Main.java -rw-r--r--. 1 root root 184 Jan 5 10 : 08 TestDeadLock$ 1 . class -rw-r--r--. 1 root root 843 Jan 5 10 : 08 TestDeadLock. class -rw-r--r--. 1 root root 1547 Jan 5 10 : 02 TestDeadLock.java -rw-r--r--. 1 root root 1066 Jan 5 10 : 08 TestDeadLock$Thread1. class -rw-r--r--. 1 root root 1066 Jan 5 10 : 08 TestDeadLock$Thread2. class [root @localhost test]# java TestDeadLock Thread1 拿到 obj1 的锁 Thread2 拿到 obj2 的锁 #这里发生了死锁,程序一直将等待下去 |
jstack命令分析
01
02
03
04
05
06
07
08
09
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
[root@localhost ~] # jstack 13399 2020-01-05 10:09:42 Full thread dump OpenJDK 64-Bit Server VM (25.232-b09 mixed mode): "Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007f5bf0001000 nid=0x3477 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007f5c1804b800 nid=0x3458 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Thread-1" #9 prio=5 os_prio=0 tid=0x00007f5c18149000 nid=0x3462 waiting for monitor entry [0x00007f5c1cac7000] java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "Thread-0" #8 prio=5 os_prio=0 tid=0x00007f5c18147000 nid=0x3461 waiting for monitor entry [0x00007f5c1cbc8000] java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f5c18117800 nid=0x345f runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f5c18114800 nid=0x345e waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f5c18105800 nid=0x345d waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f5c18103800 nid=0x345c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f5c180da000 nid=0x345b in Object.wait() [0x00007f5c1d62a000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e3408ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x00000000e3408ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f5c180d5000 nid=0x345a in Object.wait() [0x00007f5c1d72b000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e3406c00> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000e3406c00> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "VM Thread" os_prio=0 tid=0x00007f5c180cb800 nid=0x3459 runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007f5c1811a000 nid=0x3460 waiting on condition JNI global references: 5 Found one Java-level deadlock: ============================= "Thread-1" : waiting to lock monitor 0x00007f5bfc0062c8 (object 0x00000000e3466bd0, a java.lang.Object), which is held by "Thread-0" "Thread-0" : waiting to lock monitor 0x00007f5bfc004e28 (object 0x00000000e3466be0, a java.lang.Object), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1" : at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "Thread-0" : at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) |
在输出的信息中,已经看到,发现了1个死锁,关键看这个:
01
02
03
04
05
06
07
08
09
10
|
"Thread-1" : at TestDeadLock$Thread2.run(TestDeadLock.java:45) - waiting to lock <0x00000000e3466bd0> (a java.lang.Object) - locked <0x00000000e3466be0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "Thread-0" : at TestDeadLock$Thread1.run(TestDeadLock.java:25) - waiting to lock <0x00000000e3466be0> (a java.lang.Object) - locked <0x00000000e3466bd0> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) |
可以清晰的看到:
Thread2获取了 <0x00000000e3466be0> 的锁,等待获取 <0x00000000e3466bd0> 这个锁
Thread1获取了 <0x00000000e3466bd0> 的锁,等待获取 <0x00000000e3466be0> 这个锁
由此可见,发生了死锁。
更多java学习资料可关注:itheimaGZ获取
原文:https://www.cnblogs.com/zhuxiaopijingjing/p/12289928.html