死锁和哲学家进餐问题

什么是死锁

死锁的定义就是几个线程所需要的资源都在对方的手,而对方都不释放手中的所,就是不释放手里的资源,然后就这么等下去,就产生了一个死循环,就一直在等待
(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;
    }
}

测试:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值