文档章节

(十四)java多线程之死锁

天之妖星
 天之妖星
发布于 2017/05/08 14:24
字数 1126
阅读 2
收藏 0

本人邮箱: 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();
    }
}

运行结果:

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

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


打赏

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

© 著作权归作者所有

天之妖星
粉丝 1
博文 30
码字总数 58258
作品 0
深圳
高级程序员
私信 提问
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
0
0
java中高级大公司多线程面试题

1)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? lock接口在多线程和并发编...

java成功之路
2018/10/30
0
0
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0
Java面试:投行的15个多线程和并发面试题

本文由ImportNew -一杯哈希不加盐 翻译自dzone。欢迎加入翻译小组。转载请见文末要求。 多线程和并发问题已成为各种 Java 面试中必不可少的一部分。如果你准备参加投行的 Java 开发岗位面试,...

ImportNew
2018/08/23
0
0
使用JDK自带的工具jstack找出造成运行程序死锁的原因

Java多线程编程也是Java面试中经常考察的内容。刚接触Java多线程编程的朋友们,可能会不慎写出一些会导致死锁(deadlock)的应用出来。如何分析造成Java多线程的原因呢?很多时候我们在怀疑造成...

全部原谅
2018/08/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

将博客搬至CSDN

https://blog.csdn.net/qq_38157006

Marhal
12分钟前
1
0
unicode Java中求字符串长度length()和codePointCount()的区别

在计算字符串长度时,Java的两种方法length()和codePointCount()一度让我困惑,运行书上例子得到的长度值是相等的,那为什么要设定两个方法呢? 对于普通字符串,这两种方法得到的值是一样的...

泉天下
13分钟前
1
0
uin-app 一、学习理由

选择uni-app 理由 别人的理由 1. 5+ 有HTML5+和Native.js技术,HTML5+包含常用的跨平台的几百个API,能满足常规开发需求,而Native.js把40w原生api映 射成js对象,这样js可以直接调原生。HTM...

轻轻的往前走
14分钟前
1
0
方括号及其在命令行中的不同用法介绍

通配 方括号最简单的用法就是通配。你可能在知道“ Globbing”这个概念之前就已经通过通配来匹配内容了,列出具有相同特征的多个文件就是一个很常见的场景,例如列出所有 JPEG 文件: ls *.j...

Linux就该这么学
20分钟前
1
0
vecty 基础

gopherjs 是把 go 编译为 js 的工具。 vecty 是基于 gopherjs 的一种类似 React 的开发框架。 安装 gopherjs 和 vecty go get -u github.com/gopherjs/gopherjsgo get -u github.com/gopher......

electricface
21分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部