Java多线程死锁案例

产生死锁的原因

就是,两个线程互相等待着对象释放锁,一直这样僵持下去,所以导致了死锁的产生,下面这个代码就会产生一个死锁:

package com.example.demo.thread;

public class DeadLockDemo {
    private static String A = "A";
    private static String B = "B";

    public static void main(String[] args) {
        new DeadLockDemo().deadLock();
    }

    private void deadLock() {
        Thread t1 = new Thread(() -> {
          synchronized (A){
              try {
                  Thread.sleep(2000);
              }catch (InterruptedException e){
                  e.printStackTrace();
              }
              synchronized (B){
                  System.out.println("1");
              }
          }
        });
        Thread t2 = new Thread(()->{
           synchronized (B){
               synchronized (A){
                   System.out.println("2");
               }
           }
        });
        t1.start();
        t2.start();
    }
}

代码来源于《Java并发编程艺术之美》,当我运行了该程序后,一直没有输出,采用visualVM工具来进行诊断,结果如下图所示:
Java多线程死锁案例_第1张图片
从该图中,我们可以看出,DeadLockDemo类的线程的pid=6428,,可以看到红色框中提示,有死锁存在。

然后点击右上角的Thread Dump文件,来分析一下该文件的内容,具体内容如下:


2019-06-28 21:11:20
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):

"RMI TCP Connection(2)-10.2.4.117" #19 daemon prio=5 os_prio=0 tid=0x000000001c6c2800 nid=0x442c runnable [0x000000001dc6d000]
   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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        - locked <0x0000000781963ed0> (a java.io.BufferedInputStream)
        at java.io.FilterInputStream.read(FilterInputStream.java:83)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5/904339139.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x0000000781599378> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"JMX server connection timeout 18" #18 daemon prio=5 os_prio=0 tid=0x000000001c639800 nid=0x1f64 in Object.wait() [0x000000001db6f000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000781703b78> (a [I)
        at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
        - locked <0x0000000781703b78> (a [I)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"RMI Scheduler(0)" #17 daemon prio=5 os_prio=0 tid=0x000000001c638800 nid=0x305c waiting on condition [0x000000001da6f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000007814abc08> (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:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"RMI TCP Connection(1)-10.2.4.117" #16 daemon prio=5 os_prio=0 tid=0x000000001bd25800 nid=0x389c runnable [0x000000001d96d000]
   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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        - locked <0x00000007816892c0> (a java.io.BufferedInputStream)
        at java.io.FilterInputStream.read(FilterInputStream.java:83)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5/904339139.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x0000000781594850> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"RMI TCP Accept-0" #15 daemon prio=5 os_prio=0 tid=0x000000001bcdc000 nid=0x2674 runnable [0x000000001d76e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.DualStackPlainSocketImpl.accept0(Native Method)
        at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
        at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
        - locked <0x00000007814bd318> (a java.net.SocksSocketImpl)
        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:405)
        at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:377)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000003454000 nid=0x2f28 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Thread-1" #12 prio=5 os_prio=0 tid=0x000000001c654800 nid=0x42e8 waiting for monitor entry [0x000000001cf4f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.example.demo.thread.DeadLockDemo.lambda$deadLock$1(DeadLockDemo.java:27)
        - waiting to lock <0x0000000780ae7e30> (a java.lang.String)
        - locked <0x0000000780ae7e60> (a java.lang.String)
        at com.example.demo.thread.DeadLockDemo$$Lambda$2/2128227771.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001c652000 nid=0x22d4 waiting for monitor entry [0x000000001ce4e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.example.demo.thread.DeadLockDemo.lambda$deadLock$0(DeadLockDemo.java:20)
        - waiting to lock <0x0000000780ae7e60> (a java.lang.String)
        - locked <0x0000000780ae7e30> (a java.lang.String)
        at com.example.demo.thread.DeadLockDemo$$Lambda$1/2121055098.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x000000001bbd3800 nid=0x3654 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001bb51000 nid=0x3020 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001bb45800 nid=0x4050 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001bb44800 nid=0x4634 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001bb26800 nid=0x43b8 runnable [0x000000001c02e000]
   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 <0x0000000780b2bb38> (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 <0x0000000780b2bb38> (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

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001b93b800 nid=0x5dc waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001a63e800 nid=0x4770 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000000354e000 nid=0x3fdc in Object.wait() [0x000000001b92f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000780908ed0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x0000000780908ed0> (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)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001a5ca800 nid=0x1b38 in Object.wait() [0x000000001b82f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000780906bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x0000000780906bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=2 tid=0x000000001a5a7000 nid=0x3b50 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x000000000346a800 nid=0x4698 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000346c000 nid=0x4048 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000346d800 nid=0x3f94 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000346f000 nid=0x39b4 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001bc25000 nid=0x1950 waiting on condition 

JNI global references: 338


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x000000000354c3b8 (object 0x0000000780ae7e30, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000354d7a8 (object 0x0000000780ae7e60, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at com.example.demo.thread.DeadLockDemo.lambda$deadLock$1(DeadLockDemo.java:27)
        - waiting to lock <0x0000000780ae7e30> (a java.lang.String)
        - locked <0x0000000780ae7e60> (a java.lang.String)
        at com.example.demo.thread.DeadLockDemo$$Lambda$2/2128227771.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at com.example.demo.thread.DeadLockDemo.lambda$deadLock$0(DeadLockDemo.java:20)
        - waiting to lock <0x0000000780ae7e60> (a java.lang.String)
        - locked <0x0000000780ae7e30> (a java.lang.String)
        at com.example.demo.thread.DeadLockDemo$$Lambda$1/2121055098.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.


通过上面的线程Dump文件信息,我们可以看出来发生了死锁,下面也列出了java级别的锁问题和栈信息:
Java多线程死锁案例_第2张图片
并且栈信息中,可以定位到死锁发生的地方。

如果解决死锁,那是因为代码的逻辑存在问题,可以调整代码的逻辑或者业务,来避免死锁。

如何来避免死锁

  • 避免一个线程同时获取多个锁
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  • 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
    Java多线程死锁案例_第3张图片

你可能感兴趣的:(JAVA)