【java】死锁产生分析与检测分析工具

最近在看了一些关于多线程死锁分析的博客,在死锁的分析方面有了一点自己的经验,下面将它总结记录下来。

1. 死锁简介

1.1 死锁的产生

1.2 线程

1.3 锁

2. 死锁举例

3. 死锁分析

3.1 VisualVM简介

3.2 VisualVM中插件安装

3.3 线程监视

3.4 线程dump分析

3.5 Dump内容分析

3.6 利用Thread Dumps Analysis分析Thread Dump脚本


1. 死锁简介

1.1 死锁的产生

所谓死锁就是进程循环等待它方占有的资源而无限制的僵持下去的局面。

以一个简单的例子来解释:一个桥,最多可以通过一个车子,但是左右两边都来了车子,而且都上了桥,左边的车子,占用了左边的桥资源,二右边的车子,占用了右边的桥的资源。左边的车子等待右边的车子让出右边的资源,但是右边的车子却要左边的车子让出左边的资源。双方都不放弃自己所占有的资源,却都想着让对方让出自己的资源,这就会无限制的等待下去。

上述的车子表示进程,桥面代表着资源,资源只能由一个进程占有,不允许两个进程同时占有,结果两个进程等不能继续执行,如果不采取其他的措施,上述两个进程的等待状况会无限制的持续下去,这就是进程的死锁。产生死锁的根本原因就是资源有限且操作不当。

1.2 线程

线程从创建并开始运行、到不再满足继续运行时的等待或阻塞,最后再到执行完线程中定义的所有任务【run方法中的代码】而结束线程运行,具有不同的状态。

关于Java线程转储分析

阻塞和等待的区别是什么?

  • 阻塞状态的线程是在等待一个排它锁,该锁被另一个线程占用,当另一个线程释放该锁后,该线程才能获取到该锁并退出阻塞状态;
  • 等待状态的线程则是等待一段时间,由系统唤醒或者别的线程唤醒,该线程便退出等待状态。

1.3 锁

系统中,我们常常需要多线程的方式操作一个队列,这时候,为了保证所有线程能够按序访问,就需要锁来实现,实现线程同步本质上,线程同步可以理解为线程互斥,即不允许多个线程同时执行某一操作。当一个线程需要对该队列进行增删改操作时,加锁控制这些操作,使得对该队列的操作只有在获得锁的线程在执行完成所有操作之后,才能被另一个线程操作,就能实现线程安全

什么是排它锁和共享锁?

  • 排他锁:如果线程1对数据A加上排他锁后,则其他线程不能再对A加任任何类型的封锁。获准排他锁的线程既能读数据,又能修改数据。
  • 共享锁:如果线程1对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排他锁。获准共享锁的线程只能读数据,不能修改数据。

死锁发生的条件是什么?

  1. 互斥,共享资源只能被一个线程占用
  2. 占有且等待,线程 t1 已经取得共享资源 s1,尝试获取共享资源 s2 的时候,不释放共享资源 s1
  3. 不可抢占,其他线程不能强行抢占线程 t1 占有的资源 s1
  4. 循环等待,线程 t1 等待线程 t2 占有的资源,线程 t2 等待线程 t1 占有的资源

避免死锁的方法有哪些?

对于以上 4 个条件,只要破坏其中一个条件,就可以避免死锁的发生。对于第一个条件 "互斥" 是不能破坏的,因为加锁就是为了保证互斥。因此,主要破坏另外的三个条件,就可以避免死锁的产生:

  1. 一次性申请所有的资源,破坏 "占有且等待" 条件
  2.  占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源,破坏 "不可抢占" 条件
  3.  按序申请资源,破坏 "循环等待" 条件

避免死锁的java具体实现请移步至:如何避免死锁

2. 死锁举例

这里引用Java多线程之线程转储和分析(jstack)中的实例。

线程A获取锁A后,请求获取锁B,线程B获取锁B后,请求获取锁A,代码如下:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestDeadLock {

	private final static Lock lockA = new ReentrantLock(true);
	private final static Lock lockB = new ReentrantLock(true);

	public static void main(String[] args) {

		Thread t1 = new Thread(() -> {
			lockA.lock();
			try {
				System.out.println("thread-1 " + " get lockA. try to get lockB");
				lockB.lock();
			} finally {
				lockB.unlock();
				lockA.unlock();
				System.out.println("thread-1 finished.");
			}
		});
		t1.setName("Thread-1");

		Thread t2 = new Thread(() -> {
			lockB.lock();
			try {
				System.out.println("thread-2 " + " get lockB. try to get lockA ");
				lockA.lock();
			} finally {
				lockA.unlock();
				lockB.unlock();
				System.out.println("thread-2 finished.");
			}
		});
		t2.setName("Thread-2");

		t1.start();
		t2.start();
	}
}

运行效果如下图所示:

从实验结果中看到,线程1和线程2均在等待对方持有的锁释放,而陷入阻塞状态,系统进入死锁状态。

对于这样简单的多线程死锁我们可以自己分析解决死锁,当遇到更复杂的问题时,我们该如何分析并解决死锁呢?

3. 死锁分析

3.1 VisualVM简介

VisualVM 是Netbeans的profile子项目,已在JDK6.0中自带,在JDK_HOME/bin(默认是C:\Program Files\Java\jdk1.6.0_13\bin)目录下面,有一个jvisualvm.exe文件,双击打开,从UI上来看,这个软件是基于NetBeans开发的了。

VisualVM 提供了一个可视界面,双击启动 jvisualvm.exe,启动起来后和jconsole 一样同样可以选择本地和远程,如果需要监控远程同样需要配置相关参数。VisualVM可以根据需要安装不同的插件,每个插件的关注点都不同,有的主要监控GC,有的主要监控内存,有的监控线程等。

3.2 VisualVM中插件安装

1、从主菜单中选择“工具”>“插件”。
2、在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”。
3、逐步完成插件安装程序。

 

这里主要介绍三个笔者使用的插件:Visual GC、Thread Inspector和VisualVM-JConsole:

 

3.3 线程监视

有了上面的三个插件,我们就可以分析死锁了,打开VisualVM后,接着运行eclipse中的实例,可以看到VisualVM的本地目录下多了一个线程,如下图所示:

双击该进程,可以看到下图所示的效果:

点击“监视”选项卡,可以看到下图所示:

 从上图中,我们可以看到线程的cpu使用情况和gc的回收情况,以及堆的容量和堆的使用大小,装入内存中的类的总数,以及线程情况。

点击“线程”选项卡,如下图所示:

如上图所示,我们不仅可以看到程序中所有的线程,同时可以非常清除地看到所有线程的状态, 线程Thread-1和线程Thread-2都处于驻留状态,即阻塞状态。

3.4 线程dump分析

如上一节中的图中所示,VisualVM分析出目前程序中存在死锁,我们可以通过点击“线程 Dump”将各个线程运行的详细信息记录下来,进而分析死锁发生的原因,可以看到生成了如下的结果:

2019-09-25 13:40:45
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"RMI TCP Connection(6)-10.21.17.115" #20 daemon prio=5 os_prio=0 tid=0x000000001ccd9800 nid=0x3728 runnable [0x000000001e2be000]
   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 <0x0000000783e10b38> (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$5/1445897752.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:748)

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

"JMX server connection timeout 17" #17 daemon prio=5 os_prio=0 tid=0x000000001adf6000 nid=0x3adc in Object.wait() [0x000000001c5ee000]
   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 <0x0000000783e08db0> (a [I)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"RMI Scheduler(0)" #16 daemon prio=5 os_prio=0 tid=0x000000001adf4000 nid=0x3ab8 waiting on condition [0x000000001c4ee000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e18178> (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:748)

   Locked ownable synchronizers:
        - None

"RMI TCP Accept-0" #14 daemon prio=5 os_prio=0 tid=0x000000001ae55800 nid=0x13c4 runnable [0x000000001c1ee000]
   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 <0x0000000783e09080> (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:400)
        at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"DestroyJavaVM" #12 prio=5 os_prio=0 tid=0x0000000002611000 nid=0xeb0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Thread-2" #11 prio=5 os_prio=0 tid=0x000000001af21000 nid=0xbd4 waiting on condition [0x000000001b8ef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e18550> (a java.util.concurrent.locks.ReentrantLock$FairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
        at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:224)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
        at com.thread.lock.TestDeadLock.lambda$1(TestDeadLock.java:30)
        at com.thread.lock.TestDeadLock$$Lambda$2/1044036744.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x0000000783e09718> (a java.util.concurrent.locks.ReentrantLock$FairSync)

"Thread-1" #10 prio=5 os_prio=0 tid=0x000000001af1d000 nid=0x3d2c waiting on condition [0x000000001b7ef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e09718> (a java.util.concurrent.locks.ReentrantLock$FairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
        at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:224)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
        at com.thread.lock.TestDeadLock.lambda$0(TestDeadLock.java:17)
        at com.thread.lock.TestDeadLock$$Lambda$1/303563356.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x0000000783e18550> (a java.util.concurrent.locks.ReentrantLock$FairSync)

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

   Locked ownable synchronizers:
        - None

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

   Locked ownable synchronizers:
        - None

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

   Locked ownable synchronizers:
        - None

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

   Locked ownable synchronizers:
        - None

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

   Locked ownable synchronizers:
        - None

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

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001988a800 nid=0x3658 in Object.wait() [0x000000001abef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x0000000783e19020> (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=2 tid=0x0000000019869000 nid=0x1814 in Object.wait() [0x000000001aaef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x0000000783e191d8> (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=0x0000000019867800 nid=0x15dc runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002627000 nid=0xfd4 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002628800 nid=0x3fdc runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000262a800 nid=0x3c8c runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000262c800 nid=0x3e24 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001acb7800 nid=0x24d4 waiting on condition 

JNI global references: 248


Found one Java-level deadlock:
=============================
"Thread-2":
  waiting for ownable synchronizer 0x0000000783e18550, (a java.util.concurrent.locks.ReentrantLock$FairSync),
  which is held by "Thread-1"
"Thread-1":
  waiting for ownable synchronizer 0x0000000783e09718, (a java.util.concurrent.locks.ReentrantLock$FairSync),
  which is held by "Thread-2"

Java stack information for the threads listed above:
===================================================
"Thread-2":
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e18550> (a java.util.concurrent.locks.ReentrantLock$FairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
        at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:224)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
        at com.thread.lock.TestDeadLock.lambda$1(TestDeadLock.java:30)
        at com.thread.lock.TestDeadLock$$Lambda$2/1044036744.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"Thread-1":
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e09718> (a java.util.concurrent.locks.ReentrantLock$FairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
        at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:224)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
        at com.thread.lock.TestDeadLock.lambda$0(TestDeadLock.java:17)
        at com.thread.lock.TestDeadLock$$Lambda$1/303563356.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

3.5 Dump内容分析

这里以线程Thread-2为例:

"Thread-2" #11 prio=5 os_prio=0 tid=0x000000001af21000 nid=0xbd4 waiting on condition [0x000000001b8ef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000783e18550> (a java.util.concurrent.locks.ReentrantLock$FairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
        at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:224)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
        at com.thread.lock.TestDeadLock.lambda$1(TestDeadLock.java:30)
        at com.thread.lock.TestDeadLock$$Lambda$2/1044036744.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x0000000783e09718> (a java.util.concurrent.locks.ReentrantLock$FairSync)

“Thread-2”,代表线程的名字,如果有daemon,则表示该线程为守护线程,thread-2不是守护线程,所有没有daemon;

prio=5,代表线程的优先级为5【默认值】。

tid=0x000000001e69b800,代表Java的线程Id(线程在当前虚拟机中的唯一标识)。

nid=0x2340,代表线程本地标识,即线程在操作系统中的标识。

waiting on condition:线程DUMP的状态。一般有如下几种状态:

  • Runnable: 该状态表示线程具备所有可运行条件,在运行队列中等待操作系统的调度,或者正在运行。
  • Wait on condition:该状态表示线程在等待某个条件的发生。比如:等待网络读写,线程在 sleep,线程被parking。用ReentrantLock获取锁等待的时候是这个状态,ReentrantLock的condition.await()也是这个状态。
  • Waiting for monitor entry:线程没有获取过锁,在等待获取锁。用synchronized获取锁等待的时候是这个状态。
  • in Object.wait():线程已获取锁,处于运行状态,但又执行了Object.wait()方法将锁释放掉,并仍然等待该锁。

[0x000000001f18e000] :代表当前运行的线程在堆中的地址范围;

java.lang.Thread.State: WAITING (parking) :代表线程状态是WAITING ,它是被parking挂起了。

parking to wait for  <0x000000076b734700> (a java.util.concurrent.locks.ReentrantLock$FairSync) :它被parking挂起,等待获取一个ReentrantLock的公平锁0x000000076b734700

Locked ownable synchronizers: - <0x000000076b734730> (a java.util.concurrent.locks.ReentrantLock$FairSync):代表它已经拥有的锁是一个ReentrantLock的公平锁0x000000076b734730

同理可以看出,thread-1已经拥有了 一个ReentrantLock的公平锁0x000000076b734700,在等待thread-2有的一个ReentrantLock的公平锁0x000000076b734730

Found one Java-level deadlock:

Found one Java-level deadlock:
=============================
"Thread-2":
  waiting for ownable synchronizer 0x0000000783e18550, (a java.util.concurrent.locks.ReentrantLock$FairSync),
  which is held by "Thread-1"
"Thread-1":
  waiting for ownable synchronizer 0x0000000783e09718, (a java.util.concurrent.locks.ReentrantLock$FairSync),
  which is held by "Thread-2"

线程1在等线程2拥有的锁,线程2在等线程1拥有的锁。

3.6 利用Thread Dumps Analysis分析Thread Dump脚本

从前一节可以看到,我们可以通过Thread Dump后的脚本分析死锁,但是,也可以看到,Thread Dump脚本是非常大的,而且我们的举例还只是一个简单的两个线程之间产生了死锁,在多线程场景下,往往会有很多的线程,这时就肯定会导致线程脚本规模很大,人工分析就变得非常困难,因此,这里笔者介绍一下Thread Dumps Analysis工具,看一下如何非常直观地分析死锁。

网上有很多该软件的下载方式,这里不再提供,如果有需要,请留言。

复制Thread Dump产生的脚本,然后打开TDA软件,File->get logfile from clipboard,之后可以看到如下图所示:

共检测到一个死锁,死锁的原因软件也给出了分析。如有疑问,欢迎评论区留言。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
sqlcore是一套方便的基于java应用系统数据的的检查工具,方便简单,是现代系统的自动化检测的有效工具 sqlcore可以用于如下的使用场景: 1.数据库的注入分析 2.数据库sql的执行效率分析 3.平台的监控和业务逻辑的分析 4.数据库防止死锁分析 。。。。。。。。。。。。。。。。。。。 如何配置使用 1.系统需要正确的安装jdk和mysql数据,这个自己网上看看如何弄 2.配置jdbc的数据库连接 到这个文件里面修改数据库连接和密码 apache-tomcat-6.0.14.rar\apache-tomcat-6.0.14\webapps\ROOT\WEB-INF\classes\soso.properties 3.将数据库脚本sqlcore.sql导入数据库 这个脚本将创建一个sqlcore的数据库,并导入数据 4.启动压缩包里面的tomcat登录系统 http://localhost/输入验证码就可以了 5.上传你的jdbc驱动到系统 sqlcore-文件管理---上传你的jdbc 6.创建 版本 sqlcore-驱动版本---创建你的驱动版本,并管理你的jar 7.驱动方法拦截 sqlco玶e-方法编辑--选择你的驱动版本,选择你要拦截的方法 效率分析: 事物起点: 事物结束: 堆栈记录: ConnectionPropertiesImpl s0: String s1: String s2: String[] s3: String s4: String s5: String s6: int s7: 你可以对任何方法进行设置,和参数设置 8.驱动打包 sqlcore-驱动版本---选择你刚才的版本, Pack 版本,系统进行处理版本处理,处理完成后弹出打包完成的提示对话框 9.下载驱动 视图分析---》版本视图---》下载该版本 下载你刚才处理的版本 10. 配置sqlcore到你的系统里面 将下载的压缩版本打开,将里面的*.jar放到你的系统里面,并将jdbc驱动替换掉系统里面的驱动 其中SQLUtil.xml需要放到你的系统的class目录下这个是sqlcore的通信配置文件 在你的web.xml配置里面加入 <filter> <filter-name>SQLCore</filter-name> <filter-class> com.sqlutil.core.SQLCorefilter </filter-class> <init-param> <param-name>SQLCore</param-name> <param-value></param-value> </init-param> </filter> <filter> <filter-name>encode</filter-name> <filter-class> net.http.filter.CharacterEncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>SQLCore</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 这个配置便于分析每一次的请求情况并记录数据的访问情况 启动你的系统,并访问你的系统,你系统的所有sql等数据库相关情况都将传输到sqlcore平台里面 系统支持网站:http://www.ormcore.com 支持邮箱:[email protected] QQ:278082799

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值