死锁示例代码
public class TestMain implements Runnable {
//定义两把锁
static Object lock1 = new Object();
static Object lock2 = new Object();
//定义一个标志位,方便执行不同逻辑
int flag;
@Override
public void run() {
if (flag == 1) {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "获取到了lock1");
System.out.println(Thread.currentThread().getName() + "等待获取lock2");
try {
//睡眠500毫秒,确保线程二已经拿到了lock2
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "获取到了lock2");
}
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
if (flag == 2) {
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "获取到了lock2");
System.out.println(Thread.currentThread().getName() + "等待获取lock1");
try {
//睡眠500毫秒,确保线程一已经拿到了lock1
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "获取到了lock1");
}
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
public static void main(String[] args) throws InterruptedException {
TestMain testMain1 = new TestMain();
testMain1.flag = 1;
Thread thread = new Thread(testMain1, "线程一");
TestMain testMain2 = new TestMain();
testMain2.flag = 2;
Thread thread1 = new Thread(testMain2, "线程二");
thread.start();
thread1.start();
}
}
定位死锁的步骤
- 用工具或者命令行,比如top,定义java进程的pid
- 然后使用【${JAVA_HOME}/bin/jstack pid】 的命令查看具体情况
会出现如下结果:
可以清晰的看到出现问题的行数,以及线程一和线程二当前持有的锁和正在等待的锁是哪个。
总结
会出现死锁,肯定是代码逻辑出现了问题,这里只是分享一个定位死锁的方法,而如果生产环境出现了问题,是不可能先花时间去排查的,要先保证生产的可用,然后把出现死锁的信息保存下来,后面再排查和修改相应代码,当然了,最好的解决死锁方法就是避免死锁情况的出现。