死锁及处理方案

一、原因:

    线程间互相等待资源,但是又不释放自己自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。例如过独木桥,A和B分别走在桥上,想通过独木桥,但是他们都希望对方先退出,两个人就一直处在等待状态。

二、产生条件:

    1、互斥条件:一个资源每次只能被一个进程使用。独木桥每次只能通过一个人。

    2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。乙不退出桥面,甲也不退出桥面。

    3、不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺。甲不能强制乙退出桥面,乙也不能强制甲退出桥面。

    4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。如果乙不退出桥面,甲不能通过,甲不退出桥面,乙不能通过。

三、案例

public class DeadlockTest {

    public static void main(String[] args) {
        String str1 = new String("资源1");
        String str2 = new String("资源2");

        new Thread(new Lock(str1, str2), "线程1").start();
        new Thread(new Lock(str2, str1), "线程2").start();
    }
}

class Lock implements Runnable {

    private String str1;
    private String str2;

    public Lock(String str1, String str2) {
        super();
        this.str1 = str1;
        this.str2 = str2;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + "运行");
            synchronized (str1) {
                System.out.println(Thread.currentThread().getName() + "锁住"
                        + str1);
                Thread.sleep(1000);
                synchronized (str2) {
                    // 执行不到这里
                    System.out.println(Thread.currentThread().getName()
                            + "锁住-----" + str2);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最后执行的结果是

线程1运行
线程2运行
线程2锁住资源2
线程1锁住资源1

第一个线程锁住了资源1(甲占有桥的一部分资源),第二个线程锁住了资源2(乙占有桥的一部分资源),线程1企图锁住资源2(甲让乙退出桥面,乙不从),进入阻塞,线程2企图锁住资源1(乙让甲退出桥面,甲不从),进入阻塞,死锁了。

四、解决方案:

  1、锁的顺序,让两个线程获取锁的顺序是一直,则不会出现死锁

public class Demo2 {
    public static void main(String[] args) {
        Object bigGate = new Object();
        Object smallGate = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                synchronized (bigGate){
                    System.out.println(name + ":我把大门给锁了...然后我休息一下...");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(name + ":我现在要进入小门.....");
                    synchronized (smallGate){
                        System.out.println(name + ":我终于进来了.....");
                    }

                }
            }
        },"小明").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                synchronized (bigGate){
                    System.out.println(name + ":我把大门给锁了...然后我休息一下...");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(name + ":我现在要进入小门.....");
                    synchronized (smallGate){
                        System.out.println(name + ":我终于进来了.....");
                    }

                }
            }
        },"小红").start();
    }
}
小明:我把大门给锁了...然后我休息一下...
小明:我现在要进入小门.....
小明:我终于进来了.....
小红:我把大门给锁了...然后我休息一下...
小红:我现在要进入小门.....
小红:我终于进来了.....

2、在获取锁的时候加超时时间,这里我们用之前学的Lock来做例子

public class Demo3 {
    public static void main(String[] args) {
        Lock bigGate = new ReentrantLock();
        Lock smallGate = new ReentrantLock();
        Random random = new Random();
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                bigGate.lock();
                try {
                    System.out.println(name + ":我把大门给锁了...然后我休息一下...");
                    Thread.sleep(100);
                    System.out.println(name + ":我现在要进入小门.....");
                    if(smallGate.tryLock(random.nextInt(500), TimeUnit.MILLISECONDS)){
                        try {
                            System.out.println(name + ":我终于进来了.....");
                        }finally {
                            smallGate.unlock();
                        }
                    }else{
                        System.out.println(name + ":我进不去小门,算了,不进了...");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    bigGate.unlock();
                }
            }
        },"小明").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                smallGate.lock();
                try {
                    System.out.println(name + ":我把小门给锁了...然后我休息一下...");
                    Thread.sleep(100);
                    System.out.println(name + ":我现在要进入大门.....");
                    if(bigGate.tryLock(random.nextInt(500), TimeUnit.MILLISECONDS)){
                        try {
                            System.out.println(name + ":我终于进来了.....");
                        }finally {
                            bigGate.unlock();
                        }
                    }else{
                        System.out.println(name + ":我进不去大门,算了,不进了...");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    smallGate.unlock();
                }
            }
        },"小红").start();
    }
}
小明:我把大门给锁了...然后我休息一下...
小红:我把小门给锁了...然后我休息一下...
小明:我现在要进入小门.....
小红:我现在要进入大门.....
小红:我进不去大门,算了,不进了...
小明:我终于进来了.....


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值