我们在面对并发编程的时候可能会采用线程池和信号量来限制对资源的使用,但这些被限制的行为可能会导致资源死锁,java应用程序无法从死锁中恢复过来,因此在设计时一定要排除那些可能导致死锁出现的条件。
当一个线程永远的持有一个锁,并且其他线程都尝试获取这个锁时,这时他们会被阻塞。
比如,线程A持有锁L并想获得锁M的同时,线程B持有锁M并尝试获得锁L,那么这两个线程将会永远的等待下去,这个就是简单的死锁形式,抱死。
数据库在这个方面的处理比JVM要强大很多,在执行一个事物Transaction时候可能需要获取多个锁,并持有这些锁,因此两个事物间很可能发生死锁。数据库的服务器不会让这种情况发生,数据库通过在表示等待关系的有向图中搜索循环来检测到一组事物是否发生死锁,会选择一个牺牲者,牺牲者会放弃它持有的资源,其他事物会继续进行,应用程序可以重新执行被强制终止的事务,这个事务就可以成功的完成,因为跟他竞争的资源的事物都已经完成了。
以下就是一个简单的锁顺序死锁
public class LeftRightLock {
private final Object left = new Object();
private final Object right = new Object();
public void leftRight(){
synchronized (left){
synchronized (right){
System.out.print("持有left,请求right。");
}
}
}
public void rightLeft(){
synchronized (right){
synchronized (left){
System.out.print("持有right,请求left");
}
}
}
}