简介
本文将通过Java代码演示一个死锁程序,并用JDK自带的工具jstack
工具,来验证下是否真正的有死锁发生。
一.什么是死锁
两个或两个以上的线程,互相持有对方需要的资源,导致这些线程一直处于“等待”(WAITING)状态。
二.死锁的代码演示
本例演示两个线程,互相竞争对方的对象锁,造成的死锁。
public class DeadLock implements Runnable {
int condition;
static Object object1 = new Object();
static Object object2 = new Object();
public static void main(String[] args) {
DeadLock deadLock1 = new DeadLock();
DeadLock deadLock2 = new DeadLock();
deadLock1.condition = 1;
deadLock2.condition = 2;
Thread t1 = new Thread(deadLock1);
Thread t2 = new Thread(deadLock2);
t1.start();
t2.start();
}
@Override
public void run() {
System.out.println("当前是线程:" + condition);
if (condition == 1) {
synchronized (object1) {
System.out.println("线程1" + "得到object1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1,卡在下一行代码");
synchronized (object2) {
System.out.println("打印出此行,表示线程1同时获得两把锁");
}
System.out.println("线程1执行完毕");
}
}
if (condition == 2) {
synchronized (object2) {
System.out.println("线程2" + "得到object2锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2,卡在下一行代码");
synchronized (object1) {
System.out.println("打印出此行,表示线程2同时获得两把锁");
}
System.out.println("线程2执行完毕");
}
}
}
}
运行结果:
当前是线程:1
当前是线程:2
线程2得到object2锁
线程1得到object1锁
线程1,卡在下一行代码
线程2,卡在下一行代码
运行结果分析:
- 线程1持有了
object1
的锁,线程2持有了object2
的锁。 - 然后线程1去竞争
object2
锁;线程2去竞争object1
锁。 - 由于线程1并没有释放
object1
锁,线程2也并没有释放object2
锁,所以会造成死锁。
三.验证是否真正死锁
在命令行中输入:jps
,查到我们代码程序的进程号为6164
然后在命令行再输入:jstack -l 6164
,分析下程序状态:
发现程序中出现了死锁现象。
总结
明白了死锁发生的机制,我们可以想办法避免死锁发生,第一种方法是注意加锁顺序,在上面的代码实例中,我们只要在两个线程中,
对锁的竞争顺序保持一致(比如两个线程都是先竞争object1
锁,再竞争object2
锁),那死锁就不会出现了。第二种避免死锁的方式是,
设置超时时间,如果超过一定时间,自动释放锁。
在程序运行时,我们可以通过jstack
工具,查看程序运行状态,是否有死锁。