线程中的死锁问题

出现此情况是因为每个对象都有线程锁,每个对象都锁了且不释放,这样所有带锁的对象就陷入了僵持状态,为了很好地演示此案例:这里举一个哲学家就餐问题,模拟出现死锁问题,然后我们在解决这个问题,为了解决死锁,需要给线程对象规定锁的时间,比如a线程锁3000毫秒就释放,这样其他线程就可以用到之前被锁过的线程了。

我们来说一说哲学家就餐问题,这是一个很奇怪的问题,先来描述一下:在我们的脑海中先浮现出一个正方形的桌子,然后桌子边儿上坐着4位哲学家,然后桌子的四个角放着四只筷子,这样就有三种情况:

1.四个人中有人得到了一双筷子

2.四个人中有人一双筷子也没有

3.四个人中人手一支筷子(死锁)

所以我们在执行此案例的代码时会出现这三种情况,在这里我们所要解释的是第三种情况 。在这个例子中,总共出现两个做事情的对象,一个是筷子,一个是哲学家,筷子有编号,有四支筷子,有四个编号,哲学家在拿取筷子时按照编号拿,如图所示:

线程中的死锁问题

按照我们的拿取筷子要求,四位哲学家分别需要这样拿 A:左2右1 ;B:左3右2 ;C:左4右3 ; D:左1右4

首先创建筷子对象,筷子有编号

public class Chopstick {
  //筷子对象,没有业务逻辑,只是用来记录筷子编号用的
    private int num;
  //目的是当哲学家们就餐时,按照编号拿取
    public Chopstick(int num){
        this.num=num;
    }
  //使用构造方法,为筷子赋值
    public int getNum(){
        return this.num;
    }
}

有了筷子,那么我们的主角----哲学家也该登场了

public class Philosopher extends Thread{
//这是一个哲学家类,他是一个线程,因为是四个哲学家一起,同时吃饭
    private String pname;//哲学家的名字
    private Chopstick left;//哲学家左手边拿的筷子
    private Chopstick right;//哲学家右手边拿的筷子
    private long time;//用于解决死锁所需要等待的时间
//通过构造方法告诉哲学家拿取几号筷子
    public Philosopher(String pname,Chopstick left,Chopstick right,long time){
        this.pname = pname;
        this.left = left;
        this.right = right;
        this.time = time;
    }
//四位哲学家需要共同执行的规则
    public void run(){
       /**
       *try {
       *       Thread.sleep(time);
       *   //斯文的哲学家,规定好使用时间,避免了同时使用,发生死锁的情况
       *  } catch (InterruptedException e) {
       *     e.printStackTrace();
       *  }
       */
        synchronized (left) {//锁住左手边的对象
            System.out.println(this.pname+"拿起了左手边的"+this.left.getNum()+"筷子");
          //例:A哲学家左手拿起了2号筷子,
            synchronized (right){//锁住右手边的对象
                System.out.println(this.pname+"拿起了右手边的"+this.right.getNum()+"筷子");
              //A哲学家右手边拿起了1号筷子
                System.out.println(this.pname+"开始狼吞虎咽的吃起来啦");
              //OK,执行完毕,释放被锁的2号和1号筷子
            }
        }
    }
}

那么在本案例中,死锁是怎么出现的呢?---->我们规定好所有哲学家先要拿左手边的筷子,再拿右手边的筷子,都拿完后再释放筷子对象,前提是左右手都有了筷子才释放,而死锁就是出现的这么巧,四个哲学家,四只筷子,每个哲学家左手人手一支,右手都没拿筷子,所以就都不释放,拿完左手的筷子后都在等待拿右手的筷子。于是就死锁了。

public static void main(String[] args){
  //创建主方法
    Chopstick c1 = new Chopstick(1);//给四只筷子对象一个编号
    Chopstick c2 = new Chopstick(2);
    Chopstick c3 = new Chopstick(3);
    Chopstick c4 = new Chopstick(4);

    //为了解决死锁,给哲学家ABCD设置吃饭时间,这样就不会抢了
    Philosopher p1 = new Philosopher("哲学家a",c2,c1,0);
    Philosopher p2 = new Philosopher("哲学家b",c3,c2,3000);
    Philosopher p3 = new Philosopher("哲学家c",c4,c3,0);
    Philosopher p4 = new Philosopher("哲学家d",c1,c4,3000);

    p1.start();
    p2.start();
    p3.start();
    p4.start();
}

来看一下没有死锁的情况

线程中的死锁问题

有死锁的情况

线程中的死锁问题

笔者是一个正在学习后端知识的普通学者,年龄18,性别男。欢迎大家评论,提建议,讨论问题。

展开阅读全文

页面更新:2024-04-15

标签:死锁   线程   哲学家   人手   人中   筷子   左手   右手   桌子   对象   编号   案例   情况   时间   方法   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top