• (十四)java多线程之死锁以及解决方案


    本人邮箱: kco1989@qq.com
    欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco
    github: https://github.com/kco1989/kco
    代码已经全部托管github有需要的同学自行下载

    引言

    多线程如果设计的不合理的话,很可能就会出现死锁.当两个或者多个线程同事想要去获取共享资源的锁时,但每个线程都要等其他线程把他们各自的锁给释放,才能继续运行,这就是死锁.出现死锁必须具备以下几点

    • 要有两个或两个以上的线程
    • 至少有两个共享资源的锁
    • 至少存在两个线程各自拥有一个锁
    • 现在这两个线程在等待获取彼此的锁,这就出现死锁了

    比如Thread1

    synchronized(A){
        //Thread1 执行到这里
        synchronized(B){
        ...
        }
    }
    

    Thread2

    synchronized(B){
        //Thread2 执行到这里
        synchronized(A){
        ...
        }
    }
    

    以上这种情况就是死锁,如果是两个线程出现死锁,问题可能还比较好找.更复杂是有多个线程,比如线程n各自拥有锁n,然后线程1线程n-1,正在请求获取锁n+1,而线程n正在请求获取锁1,这样也或出现死锁,而且还更难被发现.

    例子

    我们要看一个例子

    public class Demo1 {
        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 (smallGate){
                        System.out.println(name + ":我把小门给锁了...然后我休息一下...");
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(name + ":我现在要进入大门.....");
                        synchronized (bigGate){
                            System.out.println(name + ":我永远都进不来啊.....");
                        }
    
                    }
                }
            },"小红").start();
        }
    }
    

    运行结果

    小明我把大门给锁了...然后我休息一下...
    小红我把小门给锁了...然后我休息一下...
    小明:我现在要进入小门.....
    小红:我现在要进入大门.....
    //然后程序到这里就一直不动了.....
    

    解决办法

    • 锁的顺序,让两个线程获取锁的顺序是一直,则不会出现死锁
    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();
        }
    }
    

    运行结果:

    小明:我把大门给锁了...然后我休息一下...
    小明:我现在要进入小门.....
    小明:我终于进来了.....
    小红:我把大门给锁了...然后我休息一下...
    小红:我现在要进入小门.....
    小红:我终于进来了.....
    
    • 在获取锁的时候加超时时间,这里我们用之前学的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();
        }
    }
    

    运行结果:

    小明:我把大门给锁了...然后我休息一下...
    小红:我把小门给锁了...然后我休息一下...
    小明:我现在要进入小门.....
    小红:我现在要进入大门.....
    小红:我进不去大门,算了,不进了...
    小明:我终于进来了.....
    

    这样也可以保证不会出现死锁.


    打赏

    如果觉得我的文章写的还过得去的话,有钱就捧个钱场,没钱给我捧个人场(帮我点赞或推荐一下)
    微信打赏
    支付宝打赏

  • 相关阅读:
    FastJson--阿里巴巴公司开源的速度最快的Json和对象转换工具
    如何去设计一个自适应的网页设计或HTMl5
    教育行业SaaS选型 需要注意的三点问题
    SaaS系列介绍之十五: SaaS知识重用
    SaaS系列介绍之十四: SaaS软件开发分析
    SaaS系列介绍之十三: SaaS系统体系架构
    SaaS系列介绍之十二: SaaS产品的研发模式
    个人总结
    用例图设计
    第二次结对作业
  • 原文地址:https://www.cnblogs.com/kco1989/p/6760893.html
Copyright © 2020-2023  润新知