死锁概念:
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
当程序执行过程中卡住时,排查下是否有死锁,可用小工具Jstack和Jconsole来进行死锁分析。
#首先通过jps查看当前运行的Java进程
$jps

#通过jstack分析死锁,可以查看到当前死锁详情
jstack 24404
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000000001ca03578 (object 0x000000076c9fc6b0, a java.lang.String),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000001ca020d8 (object 0x000000076c9fc6e0, a java.lang.String),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at runnable.DeadLockTest$2.run(DeadLockTest.java:48)
- waiting to lock <0x000000076c9fc6b0> (a java.lang.String)
- locked <0x000000076c9fc6e0> (a java.lang.String)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at runnable.DeadLockTest$1.run(DeadLockTest.java:33)
- waiting to lock <0x000000076c9fc6e0> (a java.lang.String)
- locked <0x000000076c9fc6b0> (a java.lang.String)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.

2.1、首先启动死锁测试demo程序
2.2、在cmd中运行jconsole打开图形化界面工具
2.3、选择我们需要分析的进程进行连接

2.4、选择线程选项,点击底部检测死锁功能

2.5、再点击死锁,查看各线程的死锁情况

3.1、双击jvisualvm.exe弹出界面
3.2、选择demo程序

3、点击线程,进入线程页面
4、选择Thread-1或Thread-0,点击线程Dump,进入页面,拉到最下面,可以看到
Found 1 deadlock

- package runnable;
-
- import org.omg.Messaging.SYNC_WITH_TRANSPORT;
-
- import java.util.Date;
-
- /**
- * ClassName DeadLockTest
- * description DeadLockTest
- *
- * @author : HMF
- * date: 2022/7/27 15:28
- **/
-
- public class DeadLockTest {
- private static String A="A";
- private static String B="B";
- public static void main(String[] args){
- new DeadLockTest().DeadLock();
- }
-
- public void DeadLock(){
- Thread t1=new Thread(new Runnable() {
- @Override
- public void run() {
- synchronized (A){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (B){
- System.out.println("A");
- }
- }
- }
- });
- Thread t2=new Thread(new Runnable() {
- @Override
- public void run() {
- synchronized (B){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (A){
- System.out.println("B");
- }
- }
- }
- });
- t1.start();
- t2.start();
-
- }
- }
执行时效果(控制台无任何输出,但是代码在一直运行):

从上面代码中可以看出:是因为资源竞争的问题
最后两个线程互相等待,资源相互竞争,这就是死锁。
查到有几个常见的方法:
1、避免一个线程同时获取多个锁。 ·
2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
3、尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。 ·
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
备注:
分析java线程死锁的工具,推荐使用 jstack 命令,毕竟其他2个工具在Linux中是没有的。
jstack 通过找到类入口,再找出当前线程正在等待哪个线程,然后再定位到死锁的行数。