目录
- 一、产生死锁的原因
- 二、如何避免死锁
一、产生死锁的原因
发生死锁的情况:
多个线程需要同时占用多个共享资源而发生需要互相死循环等待的情况,就是,两个线程互相等待着对象释放锁,一直这样僵持下去,所以导致了死锁的产生。
产生死锁代码:
package com.javaagent.thread;public class DieThread implements Runnable {public static Object obj1=new Object();public static Object obj2=new Object();private boolean flag;public DieThread(boolean bl){flag = bl;}@Overridepublic void run() {if(flag) {while(true) {synchronized(obj1) {try {Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}System.out.println("线程" + Thread.currentThread().getName() + "获取obj1锁对象,等待获取obj2锁对象...");synchronized(obj2) {System.out.println(Thread.currentThread().getName() + " ---- obj2.");}}}}else {while(true){synchronized(obj2) {System.out.println("线程" + Thread.currentThread().getName() + "获取obj2锁对象,等待获取obj1锁对象...");synchronized(obj1) {System.out.println(Thread.currentThread().getName() + " ---- obj1.");}}}}}
}
public class Main {public static void main(String[] args){DieThread d1=new DieThread(true);DieThread d2=new DieThread(false);final Thread t1 = new Thread(d1);final Thread t2 = new Thread(d2);t1.setName("DieThread_1");t2.setName("DieThread_2");t1.start();t2.start();}
}
输出结果:
线程DieThread_2获取obj2锁对象,等待获取obj1锁对象...
线程DieThread_1获取obj1锁对象,等待获取obj2锁对象...
采用 visualVM工具
来进行诊断,结果如下图所示:
从该图中,我们可以看出,Main的 进程ID为84114
,红框1中提示 检测到死锁
,然后我们点击红框3来查看 线程Dump
数据,如下图:
详细信息:
2020-03-04 15:02:44
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):"RMI TCP Connection(idle)" #19 daemon prio=9 os_prio=31 tid=0x00007ff1db108800 nid=0x5f03 waiting on condition [0x0000700001961000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x0000000796082e28> (a java.util.concurrent.SynchronousQueue$TransferStack)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"JMX server connection timeout 18" #18 daemon prio=9 os_prio=31 tid=0x00007ff1da87c800 nid=0x5d03 in Object.wait() [0x000070000185e000]java.lang.Thread.State: TIMED_WAITING (on object monitor)at java.lang.Object.wait(Native Method)at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)- locked <0x00000007964a9dc8> (a [I)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"RMI Scheduler(0)" #17 daemon prio=9 os_prio=31 tid=0x00007ff1da895800 nid=0x5b03 waiting on condition [0x000070000175b000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000007960ab5d8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"RMI TCP Connection(1)-10.0.5.39" #16 daemon prio=9 os_prio=31 tid=0x00007ff1d99ed800 nid=0x5903 runnable [0x0000700001657000]java.lang.Thread.State: RUNNABLEat 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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)at java.io.BufferedInputStream.read(BufferedInputStream.java:265)- locked <0x00000007963eced8> (a java.io.BufferedInputStream)at java.io.FilterInputStream.read(FilterInputStream.java:83)at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:550)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$3/657644190.run(Unknown Source)at java.security.AccessController.doPrivileged(Native Method)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- <0x0000000796299c10> (a java.util.concurrent.ThreadPoolExecutor$Worker)"RMI TCP Accept-0" #15 daemon prio=9 os_prio=31 tid=0x00007ff1d9941800 nid=0x570f runnable [0x0000700001555000]java.lang.Thread.State: RUNNABLEat java.net.PlainSocketImpl.socketAccept(Native Method)at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513)at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400)at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"Attach Listener" #13 daemon prio=9 os_prio=31 tid=0x00007ff1db028800 nid=0x5303 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"DestroyJavaVM" #12 prio=5 os_prio=31 tid=0x00007ff1da1ac000 nid=0x1403 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"DieThread_2" #11 prio=5 os_prio=31 tid=0x00007ff1d9839800 nid=0x5103 waiting for monitor entry [0x000070000134f000]java.lang.Thread.State: BLOCKED (on object monitor)at com.javaagent.thread.DieThread.run(DieThread.java:37)- waiting to lock <0x000000079585bee0> (a java.lang.Object)- locked <0x000000079585bef0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"DieThread_1" #10 prio=5 os_prio=31 tid=0x00007ff1d9835800 nid=0x4f03 waiting for monitor entry [0x000070000124c000]java.lang.Thread.State: BLOCKED (on object monitor)at com.javaagent.thread.DieThread.run(DieThread.java:26)- waiting to lock <0x000000079585bef0> (a java.lang.Object)- locked <0x000000079585bee0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:- None"Service Thread" #9 daemon prio=9 os_prio=31 tid=0x00007ff1d9835000 nid=0x4b03 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C1 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007ff1da87f800 nid=0x4903 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007ff1d98c5800 nid=0x4703 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007ff1da886000 nid=0x4503 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007ff1da884800 nid=0x4303 runnable [0x0000700000c3a000]java.lang.Thread.State: RUNNABLEat 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 <0x00000007958fc840> (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 <0x00000007958fc840> (a java.io.InputStreamReader)at java.io.BufferedReader.readLine(BufferedReader.java:389)at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)Locked ownable synchronizers:- None"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007ff1db029800 nid=0x360f runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007ff1d9820800 nid=0x3003 in Object.wait() [0x000070000092e000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x0000000795588ec8> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)- locked <0x0000000795588ec8> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)Locked ownable synchronizers:- None"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007ff1d9810800 nid=0x2e03 in Object.wait() [0x000070000082b000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x0000000795586b68> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)- locked <0x0000000795586b68> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)Locked ownable synchronizers:- None"VM Thread" os_prio=31 tid=0x00007ff1da026800 nid=0x2c03 runnable "GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ff1d9810000 nid=0x2403 runnable "GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ff1da00d000 nid=0x2603 runnable "GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ff1da00d800 nid=0x2803 runnable "GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ff1da00e000 nid=0x2a03 runnable "VM Periodic Task Thread" os_prio=31 tid=0x00007ff1da80d000 nid=0x4d03 waiting on condition JNI global references: 354Found one Java-level deadlock:
=============================
"DieThread_2":waiting to lock monitor 0x00007ff1da80ad58 (object 0x000000079585bee0, a java.lang.Object),which is held by "DieThread_1"
"DieThread_1":waiting to lock monitor 0x00007ff1da808418 (object 0x000000079585bef0, a java.lang.Object),which is held by "DieThread_2"Java stack information for the threads listed above:
===================================================
"DieThread_2":at com.javaagent.thread.DieThread.run(DieThread.java:37)- waiting to lock <0x000000079585bee0> (a java.lang.Object)- locked <0x000000079585bef0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)
"DieThread_1":at com.javaagent.thread.DieThread.run(DieThread.java:26)- waiting to lock <0x000000079585bef0> (a java.lang.Object)- locked <0x000000079585bee0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)Found 1 deadlock.
通过上面的线程Dump文件信息,我们可以看出来发生了死锁,下面也列出了java级别的锁问题和栈信息:
Found one Java-level deadlock:
=============================
"DieThread_2":waiting to lock monitor 0x00007ff1da80ad58 (object 0x000000079585bee0, a java.lang.Object),which is held by "DieThread_1"
"DieThread_1":waiting to lock monitor 0x00007ff1da808418 (object 0x000000079585bef0, a java.lang.Object),which is held by "DieThread_2"Java stack information for the threads listed above:
===================================================
"DieThread_2":at com.javaagent.thread.DieThread.run(DieThread.java:37)- waiting to lock <0x000000079585bee0> (a java.lang.Object)- locked <0x000000079585bef0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)
"DieThread_1":at com.javaagent.thread.DieThread.run(DieThread.java:26)- waiting to lock <0x000000079585bef0> (a java.lang.Object)- locked <0x000000079585bee0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)Found 1 deadlock.
并且栈信息中,可以定位到死锁发生的地方。
如果解决死锁,那是因为代码的逻辑存在问题,可以调整代码的逻辑或者业务,来避免死锁。
二、如何避免死锁
-
避免一个线程同时获取多个锁
-
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
-
尝试使用定时锁,使用
lock.tryLock(timeout)
来替代使用内部锁机制。 -
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。