什么是死锁
死锁的定义就是几个线程所需要的资源都在对方的手,而对方都不释放手中的所,就是不释放手里的资源,然后就这么等下去,就产生了一个死循环,就一直在等待
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
死锁不是程序一旦启动就会发生的,可以说她是一个偶然现象,我们必须得避免这种现象诞生
通俗的说就是张三想要李四的画,李四想要张三的书,张三说你我想一想,等几天给你答复,李死说你也再等一下,过几天再给你答复,然后就这样一直等对方的答复,然后双方都得不到对方想要的对西,然后就形成了死锁
死锁产生条件
1:互斥条件:一个资源每次只能被一个线程所使用
2:请求与保持条件:一个进程因为请求资源发生阻塞,不释放资源
3:不剥夺条件:线程一获得的资源,在未使用完之前,不能被释放
4:循环等待条件:进程之间形成一个循环等待的资源关系
哲学家进餐问题
这是一个经典的问题,哲学家1拿起自己的快子,等待哲学家2的筷子,因为他们是一起吃饭的,是以是多线程的同步发生的,此时哲学家2也在等待哲学家1的筷子,所以说两个人都必须在对方用完了给你之后才能吃饭,但是不给你的时候一更筷子吃不了,因为此时哲学家1需要哲学家2的,而哲学家2也需要哲学家1的,但是自己的也需要才能吃,是以两者又不能释放,负责都吃不了所以就都在等待了,就形成了一个死循环,就是死锁,两个哲学家都不能吃饭
代码:
我们先创建一个哲学家类
package com.thread;
/**
* @author 邓亚非
* 哲学家类
*/
public class ZheXueJia extends Thread{
private ChopStick left;//左侧筷子
private ChopStick right;//右侧筷子
private String name;//哲学家姓名
public ZheXueJia(){
}
public ZheXueJia(ChopStick left, ChopStick right, String name) {
this.left = left;
this.right = right;
this.name = name;
}
/**
* 模拟哲学家进餐
*/
@Override
public void run() {
synchronized (left){
System.out.println(this.name+"拿起了"+left.getNum()+"筷子吃饭,在等待"+ right.getNum()+"筷子");
synchronized (right){
System.out.println(this.name+"在使用"+right.getNum()+"筷子吃饭");
}
}
}
}
我们在创建一个筷子类
package com.thread;
/**
* @author 邓亚非
*/
public class ChopStick {
private String num;
public ChopStick(String num){
this.num=num;
}
/**
* 得到筷子种类
* @return
*/
public String getNum(){
return this.num;
}
}
测试代码
死锁情况:为什么会出现死锁呢:
爱线程体内,我是用了synchornized来锁资源,双层嵌套相当于两个循环,只有外层锁块结束了,才会释放,才能拿到内部锁块资源,如果出现不能释放的情况,就会一直等待,出现死锁
如图:关羽已经拿起了2号,但是此时张飞已经拿到了1号,张飞又像拿5号,此时黄忠已经拿了5号,黄忠想拿4号,此时赵云已经拿了4号,终于想拿3号,此时的两杯已经拿了3号,刘备想拿2号,此时关羽已经拿了2号,然后关羽再等待,这不就是死锁了吗?他们一直都拿不到对方的资源,都吃不到饭
非死锁情况
怎么解决死锁
这里是引用
方法一
两个锁块分开
package com.thread;
/**
* @author 邓亚非
* 哲学家类
*/
public class ZheXueJia extends Thread{
private ChopStick left;//左侧筷子
private ChopStick right;//右侧筷子
private String name;//哲学家姓名
private int time;
public ZheXueJia(){
}
public ZheXueJia(ChopStick left, ChopStick right, String name,int time) {
this.left = left;
this.right = right;
this.name = name;
this.time=time;
}
/**
* 模拟哲学家进餐
*/
@Override
public void run() {
synchronized (left){
System.out.println(this.name+"拿起了"+left.getNum()+"筷子吃饭,在等待"+ right.getNum()+"筷子");
}
synchronized (right){
System.out.println(this.name+"在使用"+right.getNum()+"筷子吃饭");
}
}
}
方法二:
标志位解决
哲学家类
package com.thread;
/**
* @author 邓亚非
* 哲学家类
*/
public class ZheXueJia extends Thread{
private ChopStick left;//左侧筷子
private ChopStick right;//右侧筷子
private String name;//哲学家姓名
public ZheXueJia(ChopStick left, ChopStick right, String name) {
this.left = left;
this.right = right;
this.name = name;
}
/**
* 模拟哲学家进餐
*/
@Override
public void run() {
while (true){
if (left.takeUp()){
System.out.println(this.name+"已经拿到了"+left.getNum()+"筷子,等待右侧的"+right.getNum()+"筷子");
if (right.takeUp()){
System.out.println(this.name+"已经拿到了"+right.getNum()+"筷子,开始吃饭了");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.name+"放下左侧筷子"+left.getNum()+"筷子,和右侧的"+right.getNum()+"筷子");
left.putDown();
right.putDown();
}else {
left.putDown();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
筷子类
package com.thread;
import java.awt.*;
/**
* @author 邓亚非
*/
public class ChopStick {
private String num;
private boolean flag=true;
public ChopStick(String num){
this.num=num;
}
/**
* 得到筷子种类
* @return
*/
public String getNum(){
return this.num;
}
/**
* 拿起筷子
*/
public boolean takeUp(){
if (flag){
flag=false;
return true;
}else {
return false;
}
}
/**
* 放下筷子
*/
public void putDown(){
flag=true;
}
}
测试: