文章目录
- 环境
- 准备工作
- 排查
-
- 姿势一:使用JVisualVM排查
- 姿势二:使用Jps+Jstack
环境
JDK8
准备工作
先准备好一个死锁程序:(程序是网上随便找的)
public class DeadLock {
public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static void main(String[] args){
Thread a = new Thread(new Lock1());
Thread b = new Thread(new Lock2());
a.start();
b.start();
}
}
class Lock1 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock1 running");
while(true){
synchronized(DeadLock.obj1){
System.out.println("Lock1 lock obj1");
Thread.sleep(3000);//获取obj1后先等一会儿,让Lock2有足够的时间锁住obj2
synchronized(DeadLock.obj2){
System.out.println("Lock1 lock obj2");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
class Lock2 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock2 running");
while(true){
synchronized(DeadLock.obj2){
System.out.println("Lock2 lock obj2");
Thread.sleep(3000);
synchronized(DeadLock.obj1){
System.out.println("Lock2 lock obj1");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行起来,会显示如下:
Lock2 running
Lock2 lock obj2
Lock1 running
Lock1 lock obj1
此时已发生死锁。针对两个问题,我们开始排查:
- 哪几个线程发生了死锁
- 死锁发生在哪几行代码
排查
姿势一:使用JVisualVM排查
JDK8提供了一个可视化工具Jvisualvm,在jdk的bin目录下可以找到。
双击打开它:
从上图可以看到这里我们的项目DeadLock正在运行中。双击打开。
点击“线程”标签,可以看到上图。
非常醒目的“检测到死锁!”红色字样。并且可以看到下面的线程图中,Thread0和Thread1两眼的红色进度条,说明已经发生阻塞。
接下来查一下到底是哪一行代码出现了问题:
单击上图中右上角的一个按钮“线程Dump”。
此时会看到长段文字,一直往下翻,可以看到:
可以看到死锁发生的位置。有了这些信息,我们就可以去review我们的代码了。
姿势二:使用Jps+Jstack
不熟悉这些常用的JVM调优工具?传送门:
通过jps获取到我们的进程id是21036,然后利用jstack看看当前的线程快照:
输入以下:
会看到控制台输出了很多信息,直接翻到最后:
到这里就成功定位到了死锁发生的代码行。
除了上述的两种方式,其实还有很多其他办法,不过大体都是利用一些监控工具。
很多商用的监控工具功能非常全面且强大,例如Jprofiler等,这里就不多介绍了。
更多资料欢迎关注: