一、死锁的定义
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
那么我们换一个更加规范的定义:集合中的每一个进程都在等待只能由本集合中的其他进程才能引发的事件,那么该组进程是死锁的。
免费视频教程推荐:java免费视频教程
二、Java 代码模拟死锁
代码示例:
public class ImitateDeadLock {
public static void main(String[] args) {
final Object a=new Object();
final Object b=new Object();
//线程 threadA 获取对象 a 的锁之后,休眠10秒, 尝试获取对象 b 的锁
Thread threadA=new Thread(new Runnable() {
@Override
public void run() {
synchronized (a) {
System.out.println("threadA 获取到对象 a 的锁");
try {
Thread.sleep(10000);
synchronized (b) {
System.out.println("threadA 获取到对象 b 的锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
//线程 threadB 获取对象 b 的锁之后,休眠10秒, 尝试获取对象 a 的锁
Thread threadB=new Thread(new Runnable() {
@Override
public void run() {
synchronized (b) {
System.out.println("threadB 获取到对象 b 的锁");
try {
Thread.sleep(10000);
synchronized (a) {
System.out.println("threadB 获取到对象 a 的锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
threadA.start();
threadB.start();
}
}
运行结果:
threadA 获取到对象 a 的锁
threadB 获取到对象 b 的锁
无限等待........
三、如何解决
1、确认问题
(1)Jps + Jstack
命令
Jps : 查看当前进程
如下所示, class 名称为 ImitateDeadLock
的进程为我们需要查看的进程。
C:Users31415> jps
1256 ImitateDeadLock
9240 Jps
7548 org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar
jstack
: 查看堆栈信息
执行 jstack 命令后,会显示出两个线程互相等待,产生了死锁。
C:Users31415>jstack 1256
Java stack information for the threads listed above:
===================================================
"Thread-1":
at ImitateDeadLock$2.run(ImitateDeadLock.java:37)
- waiting to lock <0x048b15a8> (a java.lang.Object)
- locked <0x048b15b0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at ImitateDeadLock$1.run(ImitateDeadLock.java:17)
- waiting to lock <0x048b15b0> (a java.lang.Object)
- locked <0x048b15a8> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
2、处理问题
(1)确定的顺序获取锁
例如:我们上面的 Demo 中,两个线程获取锁的顺序都为 先获取对象 a 的锁,在获取对象 b 的锁,就不会出现死锁的问题。
(2)超时放弃
当使用synchronized关键词提供的内置锁时,只要线程没有获得锁,那么就会永远等待下去,然而Lock接口提供了boolean tryLock(long time, TimeUnit unit) throws InterruptedException
方法,该方法可以按照固定时长等待锁,因此线程可以在获取锁超时以后,主动释放之前已经获得的所有的锁。通过这种方式,也可以很有效地避免死锁。
想了解更多相关教程请访问:java入门学习