发生死锁的四个必要条件:
- 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
- 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
- 环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链。
预防死锁的方法:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。只要打破四个必要条件之一就能有效预防死锁的发生:
- 打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。
- 打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。
- 打破占有且申请条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。
- 打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源。
模拟发生死锁场景:
public class DeadLock {
public static String resource1 = "resource-1";
public static String resource2 = "resource-2";
public static void main(String[] args) {
Thread thread1 = new Thread(new TaskA());
Thread thread2 = new Thread(new TaskB());
thread1.start();
thread2.start();
}
static class TaskA implements Runnable {
@Override
public void run() {
try{
System.out.println("TaskA启动");
while(true){
synchronized(DeadLock.resource1){
System.out.println("TaskA拿到了resource-1的锁");
Thread.sleep(3000);
//获取resource1后先等一会儿,让TaskB有足够的时间锁住resource2
System.out.println("TaskA想拿resource-2的锁。。。。");
synchronized(DeadLock.resource2){
System.out.println("TaskA获得到了resource-2的锁");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
static class TaskB implements Runnable {
@Override
public void run(){
try{
System.out.println("TaskB启动");
while(true){
synchronized(DeadLock.resource2){
System.out.println("TaskB拿得到了resource-2的锁");
Thread.sleep(3000);
//获取resource2后先等一会儿,让TaskA有足够的时间锁住resource1
System.out.println("TaskB想拿resource-1的锁。。。。");
synchronized(DeadLock.resource1){
System.out.println("TaskB获得到了resource-1的锁");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
使用jstack检测死锁:
-
先使用jps命令查出应用的端口号:
-
在使用jstack命令查出进程的堆栈信息:
解决方法:
通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来防止死锁的发生。
破坏占用并等待条件,预防死锁,即在任务开始的时候,就申请所有的资源。
public class DeadLock {
static Object o1 = new Object();
static Object o2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new TaskA());
Thread t2 = new Thread(new TaskB());
t1.start();
t2.start();
}
}
class TaskA implements Runnable {
@Override
public void run() {
synchronized (DeadLock.class) {
synchronized (DeadLock.o1) {
System.out.println(Thread.currentThread().getName() + "拿到了o1资源");
try {
Thread.sleep(1000);
synchronized (DeadLock.o2) {
System.out.println(Thread.currentThread().getName() + "拿到了o2资源");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class TaskB implements Runnable {
@Override
public void run() {
synchronized (DeadLock.class) {
synchronized (DeadLock.o2) {
System.out.println(Thread.currentThread().getName() + "拿到了o2资源");
try {
Thread.sleep(1000);
synchronized (DeadLock.o1) {
System.out.println(Thread.currentThread().getName() + "拿到了o1资源");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
测试结果: