Java并发编程(四)--- 死锁的发生与避免

前言

上一篇我们介绍了如何通过synchronized 来加锁保护资源。但是,不当的加锁方式可能就会导致死锁。
死锁发生的场景

最典型的就是哲学家问题,
场景:5个哲学家,5跟筷子,5盘意大利面,大家围绕桌子而坐,进行思考与进食活动。
在这里插入图片描述

哲学家的活动描述:
哲学家除了吃面、还要思考、所以要么放下左右手筷子进行思考、要么拿起两个筷子(自己两侧的)开始吃面。
哲学家从不交谈,这就很危险了,很可能会发生死锁,假设每个人都是先拿到左边的筷子,然后去拿右边的筷子,那么就可能会出现如下情况。

通过代码模拟:

public class DeadLockTest2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
int sum = 5;
Chopsticks[] chopsticks = new Chopsticks[sum];
for (int i = 0; i < sum; i++) {
chopsticks[i] = new Chopsticks();
}
for (int i = 0; i < sum; i++) {
executorService.execute(new Philosopher(chopsticks[i], chopsticks[(i + 1) % sum]));
}
}
// 筷子
static class Chopsticks {
}
//哲学家
static class Philosopher implements Runnable {
private Chopsticks left;
private Chopsticks right;

    public Philosopher(Chopsticks left, Chopsticks right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public void run() {
        try {
            //思考一段时间
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (left) {
            try {
                //拿到左边的筷子之后等待一段时间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
             synchronized (right) {
                try {
                    System.out.println("********开始吃饭");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}

}

如上程序:定义了一个哲学家类,该类的主要任务要么是思考,要么是吃饭,吃饭的话,首先拿到其左边的筷子,等待一段时间后再去拿其右边的筷子。在此处因为每个哲学家都是占用自己左边的筷子等待拿右边的筷子。所以,就会出现循环等待,导致死锁。下面我们就来查看下:
如何查看死锁的发生

我们可以通过java命令很方便的查看是否有死锁发生。首先通过jps命令查看当前程序所占的进程如下:
在这里插入图片描述

找到对应的进程之后,接着通过jstack 命令查看程序运行情况。如下:

通过上述分析我们发现死锁发生的条件是如下四个(必须同时满足):

互斥,共享资源A和B只能被一个线程占用,就是本例中的,一根筷子同一时刻只能被一个哲学家获得
占有且等待:线程T1持有共享资源A,在等待共享资源B时,不释放占用的资源,在本例中就是:哲学家1获得他左边的筷子,等待获得他右边的筷子,即使没有得到也不会放回其获得的筷子。
不可抢占:其他线程不能强行占用线程T1占用的资源,在本例中就是:每个哲学家获得的筷子不能被其他哲学家抢走。
循环等待:线程T1等待线程T2占用的资源,线程T2等待线程T1占用的资源。在本例中:所有哲学家围坐一桌,已经形成了一个申请资源的环。

 

。。。。。。。。。。。。。。。。。

版权原因,完整文章,请参考如下:Java并发编程(四)--- 死锁的发生与避免

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值