死锁问题
定义:在两个或两个以上的线程运行中,因为资源抢占而造成线程一直等待的问题。
死锁的实例:
import java.util.concurrent.TimeUnit;
/**
* 死锁演示
*/
public class ThreadDemo36 {
public static void main(String[] args) {
Object lockA=new Object();
Object lockB=new Object();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
//获取当前线程名称
String threadName=Thread.currentThread().getName();
synchronized (lockA){
//已经获取到A
System.out.println(threadName+" Get A");
//休眠一秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+" Waiting B...");
synchronized (lockB){
System.out.println(threadName+" Get B");
}
}
}
},"t1");
t1.start();
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
//获取当前线程名称
String threadName=Thread.currentThread().getName();
synchronized (lockB){
//已经获取到B
System.out.println(threadName+" Get B");
//休眠一秒
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+" Waiting A...");
synchronized (lockA){
System.out.println(threadName+" Get A");
}
}
}
},"t2");
t2.start();
}
}
运行结果:
死锁产生的四个必要条件:
- 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用(不可更改)
- 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。(不可更改)
- 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。(可以解决)
- 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。(可以解决)
当上述四个条件都成立的时候,便形成死锁。
当然,死锁的情况下如果打破上述可以解决的条件,便可让死锁消失。
- 资源一次性分配(破坏请求与保持条件)
- 可剥夺资源:在线程满足条件时,释放掉已占有的资源
- 资源有序分配(解决循环等待问题):系统为每类资源赋予一个编号,每个线程按照编号递请求资源,释放则相反