线程死锁检测方法
2017-07-31 11:36
323 查看
当多条线程以不同的顺序抢占同步资源的时候,就有可能发生死锁。
如下图所示,线程1持有锁对象A而希望获得锁对象B;另一方面,线程2持有锁对象B而希望
获得锁对象A。并且这两个线程的操作是交错执行的,因此它们会发生死锁。
当发生的死锁后,JDK自带了两个工具(jstack和JConsole),可以用来监测分析死锁的发生原因。
jstack工具用于生于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机每一条线程正在
执行的方法堆栈的集合,生成快照可以用于定位诸如线程死锁、死循环等问题。
JConsole是一种可视化监视管理工具。用于连接正在运行的JVM进程,以监控Java
应用程序性
能和跟踪 Java 中的代码。
下面以一个死锁例子来说明如何使用这两个工具来分析线程死锁。
死锁示例代码如下:
[java] view
plain copy
class SynThread implements Runnable{
int a ,b;
public SynThread(int a,int b){
this.a=a;
this.b=b;
}
@Override
public void run() {
synchronized (Integer.valueOf(a)) {//必须用valueOf()方法
synchronized (Integer.valueOf(b)) {
System.err.println("a+b=="+(a+b));
}
}
}
}
public class entry {
public static void main(String[] args) {
//循环主要是为了加大死锁概率
for(int i=0;i<100;i++){
new Thread(new SynThread(1,2)).start();
new Thread(new SynThread(2,1)).start();
}
}
}
说明:以上代码有可能发生死锁,原因是Integer.valueOf()方法作了缓存优化,对[-128,127]之间
的数字会被缓存。也就是说,循环代码中一共只创建了两个不同的对象。假设在两个synchronized
块之间发生了线程切换,那就有可能造成,线程A等待被线程B持有Integer.valueOf(1)对象,线程B
等待被线程A持有Integer.valueOf(2)对象,结果出现了死锁。(可能需要多次执行直到程序出现
阻塞现象)
JDK源代码Integer.java类对valueOf()方法的优化细节如下
[java] view
plain copy
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
使用jstack工具导出线程堆栈信息(以Windows环境为例)
1.找到运行当前程序的JVM的进程id,命令及结果如下
2.运行jstack命令,并将结果信息导出来
3.使用文本编辑器打开刚导出的文本,只要查看最后关于死锁的堆栈信息即可
4.直接从堆栈信息不能直观得到结论,没关系,我们可以画图理清线程间的调度情况
(出现闭合环路,发生死锁)
使用JConsole可视化工具检测死锁
1.直接执行JConsole工具(在jdk/bin目录下),选择目标JVM进程,然后点击连接
2.切换到“线程”标签页,点击“检测死锁”按钮
3.选择不同的线程,可以查看其资源调度信息,采用类似的方法分析,可以得出与
采用jstack分析一样的结论
如下图所示,线程1持有锁对象A而希望获得锁对象B;另一方面,线程2持有锁对象B而希望
获得锁对象A。并且这两个线程的操作是交错执行的,因此它们会发生死锁。
当发生的死锁后,JDK自带了两个工具(jstack和JConsole),可以用来监测分析死锁的发生原因。
jstack工具用于生于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机每一条线程正在
执行的方法堆栈的集合,生成快照可以用于定位诸如线程死锁、死循环等问题。
JConsole是一种可视化监视管理工具。用于连接正在运行的JVM进程,以监控Java
应用程序性
能和跟踪 Java 中的代码。
下面以一个死锁例子来说明如何使用这两个工具来分析线程死锁。
死锁示例代码如下:
[java] view
plain copy
class SynThread implements Runnable{
int a ,b;
public SynThread(int a,int b){
this.a=a;
this.b=b;
}
@Override
public void run() {
synchronized (Integer.valueOf(a)) {//必须用valueOf()方法
synchronized (Integer.valueOf(b)) {
System.err.println("a+b=="+(a+b));
}
}
}
}
public class entry {
public static void main(String[] args) {
//循环主要是为了加大死锁概率
for(int i=0;i<100;i++){
new Thread(new SynThread(1,2)).start();
new Thread(new SynThread(2,1)).start();
}
}
}
说明:以上代码有可能发生死锁,原因是Integer.valueOf()方法作了缓存优化,对[-128,127]之间
的数字会被缓存。也就是说,循环代码中一共只创建了两个不同的对象。假设在两个synchronized
块之间发生了线程切换,那就有可能造成,线程A等待被线程B持有Integer.valueOf(1)对象,线程B
等待被线程A持有Integer.valueOf(2)对象,结果出现了死锁。(可能需要多次执行直到程序出现
阻塞现象)
JDK源代码Integer.java类对valueOf()方法的优化细节如下
[java] view
plain copy
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
使用jstack工具导出线程堆栈信息(以Windows环境为例)
1.找到运行当前程序的JVM的进程id,命令及结果如下
2.运行jstack命令,并将结果信息导出来
3.使用文本编辑器打开刚导出的文本,只要查看最后关于死锁的堆栈信息即可
4.直接从堆栈信息不能直观得到结论,没关系,我们可以画图理清线程间的调度情况
(出现闭合环路,发生死锁)
使用JConsole可视化工具检测死锁
1.直接执行JConsole工具(在jdk/bin目录下),选择目标JVM进程,然后点击连接
2.切换到“线程”标签页,点击“检测死锁”按钮
3.选择不同的线程,可以查看其资源调度信息,采用类似的方法分析,可以得出与
采用jstack分析一样的结论
相关文章推荐
- 线程死锁检测方法
- java线程死锁的检测方法
- 查找MySQL线程中死锁的ID的方法
- 详解SQL死锁检测的方法
- Unity之C#——异步委托开启线程,三种方法检测结束
- java 线程死锁的检测
- Android中检测当前是否为主线程最可靠的解决方法
- sql server 死锁一般常用的方法检测
- Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript.
- Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript.
- java基础25 线程的常用方法、线程安全问题、死锁现象
- 引起线程死锁的一种情况及解决方法
- Java线程死锁查看分析方法
- 查找MySQL线程中死锁的ID的方法
- Thread Dump线程死锁检测工具(JStack)的使用详解
- 线程的笔记1 wait yield join interrupt deamon 死锁使用方法
- Java-java线程:两个实现方法,死锁现象,线程通讯,线程停止等
- 详解SQL死锁检测的方法
- 线程中其他方法以及死锁
- Advanced Techniques To Avoid And Detect Deadlocks In .NET Apps(线程死锁和检测-译【待续】)