资讯专栏INFORMATION COLUMN

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

wendux / 784人阅读

摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言多线程如果设计的不合理的话很可能就会出现死锁当两个或者多个线程同事想要去获取共享资源的锁时但每个线程都要等其他线程把他们各自的锁给释放才能继续运行这就是死锁出现死锁必须具

本人邮箱:
欢迎转载,转载请注明网址 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();
    }
}

运行结果:

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

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

打赏

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67041.html

相关文章

  • 超详细的Java面试题总结(二)Java基础知识篇

    摘要:超详细的面试题总结一之基本知识多线程和虚拟机创建线程有几种不同的方式你喜欢哪一种为什么继承类实现接口应用程序可以使用框架来创建线程池实现接口。死亡线程方法执行结束,或者因异常退出了方法,则该线程结束生命周期。死亡的线程不可再次复生。 超详细的Java面试题总结(一)之Java基本知识 多线程和Java虚拟机 创建线程有几种不同的方式?你喜欢哪一种?为什么? 继承Thread类 实现R...

    wangjuntytl 评论0 收藏0
  • 我的阿里路+Java面经考点

    摘要:我的是忙碌的一年,从年初备战实习春招,年三十都在死磕源码,三月份经历了阿里五次面试,四月顺利收到实习。因为我心理很清楚,我的目标是阿里。所以在收到阿里之后的那晚,我重新规划了接下来的学习计划,将我的短期目标更新成拿下阿里转正。 我的2017是忙碌的一年,从年初备战实习春招,年三十都在死磕JDK源码,三月份经历了阿里五次面试,四月顺利收到实习offer。然后五月怀着忐忑的心情开始了蚂蚁金...

    姘搁『 评论0 收藏0
  • 线程死锁就是这么简单

    摘要:此时线程需要锁才能继续往下执行。但是线程的锁并没有释放,线程的锁也没有释放。 前言 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 AQS简简单单过一遍 Lock锁子类了解一下 线程池你真不来了解一下吗? 本篇主要是讲解死锁,这是我在多线程的最后一篇了。主要将多线程...

    winterdawn 评论0 收藏0
  • Java线程进阶(十四)—— J.U.Catomic框架:AtomicReference

    摘要:但是,有些操作会依赖于对象的变化过程,此时的解决思路一般就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么就会变成。四的引入就是上面所说的加了版本号的。 showImg(https://segmentfault.com/img/remote/1460000016012188); 本文首发于一世流云的专栏:https://segmentfault.com/blo...

    aboutU 评论0 收藏0
  • Java基础学习——线程线程间通信(安全问题、等待唤醒机制)

    摘要:线程间通信其实就是多个线程操作同一个资源,但动作不同。同步前提是多线程。将该线程载入线程池,等待唤醒。该方法抛出异常,故需要配合使用随机唤醒线程池中一线程。线程为了检测死锁,它需要递进地检测所有被请求的锁。 线程间通信 其实就是多个线程操作同一个资源,但动作不同。示例:在某个数据库中,Input输入人的姓名,性别,Output输出,两个线程同时作用。思考:1.明确哪些代码是多线程操作的...

    CocoaChina 评论0 收藏0

发表评论

0条评论

wendux

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<