1、死锁的概念
概念:死锁是指两个对象分别持有锁,并且相互等待对方释放锁的现象。
实例:A和B两个人吃意面,A拿勺子,B拿叉子,而要吃意面勺子和叉子都需要。A拿着勺子等着B放下叉子,B拿着叉子等着A放下勺子,这样两个人僵持下去,出现死锁。
/**
* @author :16140
* @description : 死锁的发生场景
* @create :2021-08-07 20:18:00
*/
public class DeadLock {
public static void main(String[] args) {
Person person1 = new Person(0,"张三");
Person person2 = new Person(1,"李四");
person1.start();
person2.start();
}
}
/**
* 勺子
*/
class Spoon{
}
/**
* 叉子
*/
class Fork{
}
/**
* 人
*/
class Person extends Thread{
static Spoon spoon = new Spoon();
static Fork fork = new Fork();
int choice;
String personName;
public Person(int choice,String personName){
this.choice = choice;
this.personName = personName;
}
@Override
public void run() {
try {
eat();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void eat() throws InterruptedException {
if (choice == 0){
synchronized (spoon){
System.out.println(this.personName + "拿到了勺子");
Thread.sleep(1000);
synchronized (fork){
System.out.println(this.personName + "拿到了叉子");
}
}
}else{
synchronized (fork){
System.out.println(this.personName + "拿到了叉子");
Thread.sleep(1000);
synchronized (spoon){
System.out.println(this.personName + "拿到了勺子");
}
}
}
}
}
2、死锁的产生条件
- 某个资源在某时间内只允许一个线程操作;
- 该资源不能被夺走,只能由该线程自己释放;
- 某线程占用了一个资源,还想占用其他资源;
- 循环关系,即A需要B的资源,B需要C的资源,C需要A的资源。
如上面例子:
- 表示spoon和fork只能由一个线程占用;
- 表示两个人拿了一个资源还想要另一个资源;
- 表示这个资源你抢不走,只能等待释放;
- 表示这两个资源彼此形成循环,导致哪一方也不会提前释放。
3、解决办法
4个条件必须都满足才行。
解决方式:
- 可以多个线程同时使用这个资源,但是还是有多线程问题;
- 如果某个线程的资源不能夺走,而它又访问了其他资源而没拿到,那么就释放它,这样就允许其他线程访问。感觉这种方式非常礼貌,吃饭要排队,那我就先不排了,你们先吃。但是这种方式实现起来比较困难,所以很少使用;
- 既然你占了一个资源,还想占另一个,那么不如直接让一个拿到全部资源再执行。(《图解Java多线程设计模式》中的成对拿取方式)
- 既然是循环,那么不如按照一定分配次序来拿,这种方式不会造成资源的闭环。(《图解Java多线程设计模式》中的以相同顺序拿取资源)