JUC高并发编程
六、多线程锁
6.4)死锁
6.4.1)什么是死锁
死锁:两个或者两个以上进程在执行过程中,因为争夺资源而造成一种互相等待的现象,如果没有外力干涉,它们就无法在执行下去,会卡在这里,如下图所示:
线程A持有锁A试图获取锁B,线程B持有锁B试图获取锁A,代码实现如下:
/**
* 演示死锁
*/
public class DeadLock {
//创建两个对象
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (a) {
System.out.println(Thread.currentThread().getName()+" 持有锁a,试图获取锁b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName()+" 获取锁b");
}
}
},"A").start();
new Thread(()->{
synchronized (b) {
System.out.println(Thread.currentThread().getName()+" 持有锁b,试图获取锁a");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName()+" 获取锁a");
}
}
},"B").start();
}
}
输出:
A 持有锁a,试图获取锁b B 持有锁b,试图获取锁a
6.4.2)验证是否死锁
6.4.2.1)查看运行的Java进程
命令: jps -l
E:\StudyCode\JUC\JucStudy>jps -l
1556 sun.tools.jps.Jps
9992
11884 com.study.sync.DeadLock
13964 org.jetbrains.jps.cmdline.Launcher
8188 org.jetbrains.jps.cmdline.Launcher
6.4.2.2)查看堆栈信息
查看DeadLock的堆栈信息,命令:jstack 进程号
E:\StudyCode\JUC\JucStudy>jstack 11884
2022-05-11 15:35:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):
"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000000003063800 nid=0x984 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"B" #13 prio=5 os_prio=0 tid=0x000000001ad5d800 nid=0x3b6c waiting for monitor entry [0x000000001b72f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.study.sync.DeadLock.lambda$main$1(DeadLock.java:38)
- waiting to lock <0x00000000d63fde08> (a java.lang.Object)
- locked <0x00000000d63fde18> (a java.lang.Object)
at com.study.sync.DeadLock$$Lambda$2/1078694789.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"A" #12 prio=5 os_prio=0 tid=0x000000001ad5b800 nid=0x498c waiting for monitor entry [0x000000001b62f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.study.sync.DeadLock.lambda$main$0(DeadLock.java:24)
- waiting to lock <0x00000000d63fde18> (a java.lang.Object)
- locked <0x00000000d63fde08> (a java.lang.Object)
at com.study.sync.DeadLock$$Lambda$1/1324119927.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x0000000019f9a000 nid=0x3b00 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x0000000019f48800 nid=0x4988 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x0000000019f10800 nid=0x6c0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000000019f0b000 nid=0x450c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0000000019f02800 nid=0x47a0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x0000000019f09000 nid=0x840 runnable [0x000000001a72f000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x00000000d63883f8> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x00000000d63883f8> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:47)
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000019e6c800 nid=0x3a48 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000019ec0000 nid=0x170 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000019e51800 nid=0x1ecc in Object.wait() [0x000000001a42f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d6208ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000d6208ed0> (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=2 tid=0x0000000019e50800 nid=0x40ac in Object.wait() [0x000000001a32e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d6206bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d6206bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x0000000018059000 nid=0x4abc runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003079000 nid=0x1110 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000307a800 nid=0x320c runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000307c000 nid=0xdd8 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000307e800 nid=0x2920 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000003081000 nid=0x3b08 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000003082000 nid=0x3e18 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000003085000 nid=0x3ab0 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000003086800 nid=0x4578 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000000019f9b800 nid=0x4644 waiting on condition
JNI global references: 317
Found one Java-level deadlock:
=============================
"B":
waiting to lock monitor 0x000000000315bca8 (object 0x00000000d63fde08, a java.lang.Object),
which is held by "A"
"A":
waiting to lock monitor 0x000000000315e5e8 (object 0x00000000d63fde18, a java.lang.Object),
which is held by "B"
Java stack information for the threads listed above:
===================================================
"B":
at com.study.sync.DeadLock.lambda$main$1(DeadLock.java:38)
- waiting to lock <0x00000000d63fde08> (a java.lang.Object)
- locked <0x00000000d63fde18> (a java.lang.Object)
at com.study.sync.DeadLock$$Lambda$2/1078694789.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"A":
at com.study.sync.DeadLock.lambda$main$0(DeadLock.java:24)
- waiting to lock <0x00000000d63fde18> (a java.lang.Object)
- locked <0x00000000d63fde08> (a java.lang.Object)
at com.study.sync.DeadLock$$Lambda$1/1324119927.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
发现在堆栈信息中 Found 1 deadlock ,说明确实发生了死锁
6.4.3)产生死锁的原因
产生死锁的原因有以下三点:
-
系统资源不足;
-
进程运行推进顺序不合适
-
资源分配不当