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


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

  • 相关阅读:
    “#ifdef __cplusplus extern "C" { #endif”的定义
    【原创】分布式之redis复习精讲
    python爬虫入门(六) Scrapy框架之原理介绍
    PYTHON面试
    14.Ubuntu基本命令
    python爬虫入门(五)Selenium模拟用户操作
    python爬虫入门(四)利用多线程爬虫
    python爬虫入门(三)XPATH和BeautifulSoup4
    python爬虫入门(一)urllib和urllib2
    7.Ajax
  • 原文地址:https://www.cnblogs.com/binarylei/p/8999701.html
Copyright © 2011-2022 走看看