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。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值