栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java多线程8-死锁

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java多线程8-死锁

一、死锁定义

  通过锁机制解决了线程同步问题,但同时带来了一个新问题——死锁。

  死锁是指多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,导致线程循环等待进程停止的问题。当某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”问题。

  死锁图示:

二、死锁代码示例
// 死锁示例
public class ThreadDemo3 implements Runnable {
    int type;
    C1 c1;
    C2 c2;

    ThreadDemo3(int type, C1 c1, C2 c2) {
        this.type = type;
        this.c1 = c1;
        this.c2 = c2;
    }
    public void run() {
        if(type == 1) {
            // 占有c1
            synchronized(c1) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
                // 已经占有c1,未释放c1,想申请c2
                synchronized(c2) {
                    System.out.println(Thread.currentThread().getName() + " get c2");
                }
            }
        }
        if(type == 2) {
            // 占有c2
            synchronized(c2) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
                // 已经占有c2,未释放c1,想申请c1
                synchronized(c1) {
                    System.out.println(Thread.currentThread().getName() + " get c1");
                }
            }
        }
    } 
}

// 共享资源1
class C1 { }

// 共享资源2
class C2 { }

  执行:

public static void main(String[] args) {
    C1 c1 = new C1();
    C2 c2 = new C2();
    ThreadDemo3 t1 = new ThreadDemo3(1, c1, c2);
    ThreadDemo3 t2 = new ThreadDemo3(2, c1, c2);
    new Thread(t1).start();
    new Thread(t2).start();
}

  输出:

  可以看到,程序会一直停留,t1会一直获取不到c2,t2也一直获取不到c1。

三、死锁条件及解决方案

  如果系统中以下四个条件同时成立,那么就能引起死锁:

  • 互斥:资源必须处于非共享模式,即一次只有一个线程可以使用。如果另一线程申请该资源,那么必须等待直到该资源被释放为止。
  • 占有并等待:一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他线程所占有。
  • 非抢占:资源不能被抢占。只能在持有资源的线程完成任务后,该资源才会被释放。
  • 循环等待:有一组等待线程 {P0, P1,..., Pn}, P0 等待的资源被 P1 占有,P1 等待的资源被 P2 占有,…,Pn-1 等待的资源被 Pn 占有,Pn 等待的资源被 P0 占有。

  我们只要破坏上面任意一个或多个条件,就能破坏死锁。

  将上面的示例代码run()方法修改,t1先释放c1后,再去申请c2;或者t2先释放c2后,再去申请c1。都能破坏死锁。

public void run() {
    if(type == 1) {
        // 占有c1
        synchronized(c1) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        }
        // 先释放c1,再申请c2
        synchronized(c2) {
            System.out.println(Thread.currentThread().getName() + " get c2");
        }
    }
    if(type == 2) {
        // 占有c2
        synchronized(c2) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            // 已经占有c2,未释放c1,想申请c1
            synchronized(c1) {
                System.out.println(Thread.currentThread().getName() + " get c1");
            }
        }
    }
}

  输出:

  可以看到,死锁已经解开。t1获取到了c2,t2获取到了c1。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/690828.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号