死锁的成因和解决方案

死锁的成因

关于死锁的情况有三种

1.一个线程,一把锁

这种情况是当这个线程使用锁后没有进行解锁,然后再次使用锁的时候就会出现死锁的情况.

当然,这个只能针对不可重入锁,对于可重入锁不造成影响.

2.两个线程两把锁

出现以下代码时就可能造成死锁

public class Main{
    public static Object o1 = new Object();
    public static Object o2 = new Object();
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (o1){
                synchronized (o2){
                    System.out.println("t1");
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            synchronized (o2){
                synchronized (o1){
                    System.out.println("t2");
                }
            }
        });
        t2.start();
    }
}

当t1和t2同时进行第一把加锁就会出现死锁的情况

3.N个线程,M把锁

线程数量和锁数量更多了,就更容易死锁了

著名的哲学家的就餐问题

 

这五个哲学家随机的拿起筷子吃饭和放下筷子

如果他想拿起筷子,被别人占用了,就会就行等待,等的过程中不会放下已经拿起的筷子;

假设这五个哲学家同时拿起左手边的筷子就死锁了

但在线程中更加复杂,更容易出现死锁

死锁的四个必要条件

1.互斥使用,一个线程拿到一把锁之后,另一个线程不能使用.(锁的基本特点)

2.不可抢占,一个线程拿到锁,只能自己主动释放,不能是被其他线程强行占有(锁的基本特点)

3.请求和保持,"吃着碗里的看着锅里的", 在拿到一号锁之后,再想拿二号锁,并且不会放掉一号锁(代码的特点)

4.循环等待,形成一个进程等待环路,环路中的每个进程所占有的资源都在被别的进程所申请(代码的特点)

四个条件缺一不可

如何避免死锁

一个简单有效的办法,就是破解循环等待这个条件.

针对锁进行编号,如果需要同时获取多把锁,约定加锁顺序,务必是先对小的编号进行加锁,后对大的编号加锁

比如在哲学家就餐问题当中:

 约定每个哲学家都只能先去拿一号筷子再去拿二号筷子,一号筷子如果被拿走了则等待

在我们写代码的时候注意加锁顺序就行了.

我们约定先对小号锁进行加锁,在加大号锁,然后所有线程都遵守这个顺序即可.

public class Main{
    public static Object o1 = new Object();
    public static Object o2 = new Object();
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (o1){
                synchronized (o2){
                    System.out.println("t1");
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            synchronized (o1){
                synchronized (o2){
                    System.out.println("t2");
                }
            }
        });
        t2.start();
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值