zoukankan      html  css  js  c++  java
  • Java Thread系列(七)死锁

    Java Thread系列(七)死锁

    当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

    线程 A 当前持有互斥所锁 lock1,线程 B 当前持有互斥锁 lock2。接下来,当线程 A 仍然持有 lock1 时,它试图获取 lock2,因为线程 B 正持有 lock2,因此线程 A 会阻塞等待线程 B 对 lock2 的释放。如果此时线程 B 在持有 lock2 的时候,也在试图获取 lock1,因为线程 A 正持有 lock1,因此线程 B 会阻塞等待 A 对 lock1 的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。

    下面给出一个两个线程间产生死锁的示例,如下:

    /**
     * 多个线程挣抢同一份资源,容易造成死锁
     * @author: leigang
     * @version: 2018-05-05
     */
    public class DeadThread {
    
        public static void main(String[] args) {
            Object goods = new Object();
            Object money = new Object();
    
            new Test1(goods, money).start();
            new Test2(goods, money).start();
    
        }
    
        static class Test1 extends Thread {
            private Object goods;
            private Object money;
    
            public Test1(Object goods, Object money) {
                this.goods = goods;
                this.money = money;
            }
    
            @Override
            public void run() {
                while (true) {
                    test();
                }
            }
    
            public void test() {
                synchronized (goods) {  // (1)
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (money) {
                    }
                }
                System.out.println(Thread.currentThread().getName() + "先交货再给钱");
            }
        }
    
        static class Test2 extends Thread {
            private Object goods;
            private Object money;
    
            public Test2(Object goods, Object money) {
                this.goods = goods;
                this.money = money;
            }
    
            @Override
            public void run() {
                while (true) {
                    test();
                }
            }
    
            public void test() {
                synchronized (money) {  // (2)
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (goods) {
                    }
                }
                System.out.println(Thread.currentThread().getName() + "先给钱再交货");
            }
        }
    }
    

    说明:线程 1 持有 goods 锁并打算获取 money 锁,但线程 2 已经持有 money 锁并打算获取 goods 锁,由于这两个锁都被锁住,所以这两个线程都不能获取相应的锁,这样就产生了死锁。

    大部分代码并不容易产生死锁,死锁可能在代码中隐藏相当长的时间,等待不常见的条件地发生,但即使是很小的概率,一旦发生,便可能造成毁灭性的破坏。避免死锁是一件困难的事,遵循以下原则有助于规避死锁:

    1、只在必要的最短时间内持有锁,考虑使用同步语句块代替整个同步方法;

    2、尽量编写不在同一时刻需要持有多个锁的代码,如果不可避免,则确保线程持有第二个锁的时间尽量短暂;

    3、创建和使用一个大锁来代替若干小锁,并把这个锁用于互斥,而不是用作单个对象的对象级别锁;

    既然多个线程操作同一个对象容易产生死锁,那么如何解决这个问题呢?一个经典的解决方案是 生产者-消费者模式

    参考:

    《Java 并发编程》:http://www.importnew.com/20638.html


    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    【整理】数组面试题集锦
    【整理】二叉树面试题集锦
    【转】C++怎么设计只能在堆或者栈分配空间的类以及定义一个不能被继承的类
    【转】面试题:最长回文子串
    【转】后缀数组求最长重复子串
    【转】linux硬链接与软链接
    【转】随机函数面试题
    【转】C++ 重载、覆盖和隐藏
    分类算法评估指标
    Pandas_对某列的内容分列
  • 原文地址:https://www.cnblogs.com/binarylei/p/8999701.html
Copyright © 2011-2022 走看看