死锁
死锁就是两个或以上线程互相争抢对方资源,导致没有任何一个线程能获得所需所有资源的一种僵持状态。死锁下的线程是 BLOCKED 状态。
下面我们来使用Synchronized 关键字 造一个死锁。
ServiceOne类:
public class ServiceOne {
private ServiceTwo serviceTwo;
private final Object LOCK_ONE = new Object();
public void setServiceTwo(ServiceTwo serviceTwo) {
this.serviceTwo = serviceTwo;
}
public void soMethod1(){
synchronized (LOCK_ONE){
System.out.println("soMethod1 get LOCK_ONE.");
System.out.println("handle soMethod1.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
serviceTwo.stMethod1();
}
}
public void soMethod2(){
synchronized (LOCK_ONE){
System.out.println("soMethod2 get LOCK_ONE.");
System.out.println("handle soMethod2.");
}
}
}
ServiceTwo类:
public class ServiceTwo {
private ServiceOne serviceOne;
private final Object LOCK_TWO = new Object();
public void setServiceOne(ServiceOne serviceOne) {
this.serviceOne = serviceOne;
}
public void stMethod1() {
synchronized (LOCK_TWO){
System.out.println("stMethod1 get LOCK_TWO");
System.out.println("handle.");
}
}
public void stMethod2(){
synchronized (LOCK_TWO){
System.out.println("stMethod2 get LOCK_TWO.");
System.out.println("handle stMethod2.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
serviceOne.soMethod2();
}
}
}
测试代码:
public class TestService {
public static void main(String[] args) {
ServiceOne serviceOne = new ServiceOne();
ServiceTwo serviceTwo = new ServiceTwo();
serviceOne.setServiceTwo(serviceTwo);
serviceTwo.setServiceOne(serviceOne);
new Thread(){
@Override
public void run() {
serviceOne.soMethod1();
}
}.start();
new Thread(){
@Override
public void run() {
serviceTwo.stMethod2();
}
}.start();
}
}
输出结果:
soMethod1 get LOCK_ONE.
handle soMethod1.
stMethod2 get LOCK_TWO.
handle stMethod2.
然后线程一直等待。
分析:
首先我们假设线程1和线程2同时启动(虽然不是同时启动,但是相差远小于1s)
通过上图可以知道,线程1持有LOCK_ONE
, 想获取LOCK_TWO
, 而线程2持有LOCK_TWO
, 想获取LOCK_ONE
, 所以导致了死锁。
下面我们通过 jstack 查看线程情况。
首先使用命令jps
查询线程。
F:\1SourceCode\java-concurrency> jps
12036 Jps
12600
22824 TestService
8104 org.eclipse.equinox.launcher_1.5.700.v20200207-2156.jar
11196 Launcher
然后使用jstack
F:\1SourceCode\java-concurrency>jstack 22824
2020-05-15 21:56:39
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.91-b15 mixed mode):
...
"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000000002f62800 nid=0x5eac waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #13 prio=5 os_prio=0 tid=0x000000001ebc9000 nid=0x6248 waiting for monitor entry [0x000000001f99e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod2(ServiceOne.java:30)
- waiting to lock <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod2(ServiceTwo.java:27)
- locked <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$2.run(TestService.java:20)
"Thread-0" #12 prio=5 os_prio=0 tid=0x000000001ebc8000 nid=0x4584 waiting for monitor entry [0x000000001f89f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod1(ServiceTwo.java:13)
- waiting to lock <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod1(ServiceOne.java:23)
- locked <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$1.run(TestService.java:14)
"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001eb15800 nid=0x6320 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
...
JNI global references: 362
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000000000305dff8 (object 0x000000076b3b44f8, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000000305b768 (object 0x000000076b3b7a20, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod2(ServiceOne.java:30)
- waiting to lock <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod2(ServiceTwo.java:27)
- locked <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$2.run(TestService.java:20)
"Thread-0":
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod1(ServiceTwo.java:13)
- waiting to lock <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod1(ServiceOne.java:23)
- locked <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$1.run(TestService.java:14)
Found 1 deadlock.
可以看到 Found 1 deadlock
. 表示发现一个死锁。我们再拿出我们创建的 Thread-0
和 Thread-1
两个线程信息分析:
"Thread-1" #13 prio=5 os_prio=0 tid=0x000000001ebc9000 nid=0x6248 waiting for monitor entry [0x000000001f99e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod2(ServiceOne.java:30)
- waiting to lock <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod2(ServiceTwo.java:27)
- locked <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$2.run(TestService.java:20)
"Thread-0" #12 prio=5 os_prio=0 tid=0x000000001ebc8000 nid=0x4584 waiting for monitor entry [0x000000001f89f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.example.chapter8.deadLockDemo.ServiceTwo.stMethod1(ServiceTwo.java:13)
- waiting to lock <0x000000076b3b7a20> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.ServiceOne.soMethod1(ServiceOne.java:23)
- locked <0x000000076b3b44f8> (a java.lang.Object)
at org.example.chapter8.deadLockDemo.TestService$1.run(TestService.java:14)
可以看到 Thread-1
locked <0x000000076b3b7a20> , waiting to lock <0x000000076b3b44f8>, 而 Thread-0
locked <0x000000076b3b44f8> , waiting to lock <0x000000076b3b7a20> , 这里也可以明显的看到锁的信息。 并且都处于BLOCKED状态。所以死锁情况下的线程处于 BLOCKED .