线程死锁.

上一篇:线程中断

线程死锁

定义:死锁指的是两个及两个以上的线程在执行中,因争夺资源而造成的互相等待的现象,在无外力的作用下这些线程会一直等待而无法继续执行。

死锁产生条件:
1、互斥条件:对象被一个线程占用,那么其他线程要等这个线程用完才能去占用;
在这里插入图片描述

2、请求并持有条件:一个线程占用了一个资源,执行过程中还去请求其他的资源;
在这里插入图片描述

3、不可剥夺条件:一个对象一旦被某个线程占用,必须要等到这个线程释放这个对象的锁,其他线程才可以去竞争;

4、环路等待条件:发生死锁时,必然存在“线程-资源”环形链,就是说必定线程B在等待线程A所持有的资源;
在这里插入图片描述
避免死锁的方法:破坏死锁产生的四个条件中的至少一个;由于操作系统限制,目前只能破坏【请求并持有条件】和【环路等待条件】

死锁代码示例:

package com.dwk.thread;

/**
 * @author duweikun
 * @describe 线程死锁测试类
 * @date 2021/10/15
 */
public class DeadLockTest {

    private Object A = new Object();
    private Object B = new Object();

    public void test(){

        Thread thread1 = new Thread(() -> {
            try {
            //为了让线程2先占用对象B,线程1先休眠1秒
                Thread.sleep(1000);
                synchronized (A){
                    System.out.println("线程1占用对象A");
                    synchronized (B){
                        System.out.println("线程1占用对象B");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                synchronized (B) {
                    System.out.println("线程2占用对象B");
                    //为了让线程1先占用对象A,让线程2先休眠1秒
                    Thread.sleep(1000);
                    synchronized (A) {
                        System.out.println("线程2占用对象A");
                    }
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();

    }

    public static void main(String[] args) {
        DeadLockTest deadLockTest = new DeadLockTest();
        deadLockTest.test();
    }

}

执行结果:
在这里插入图片描述
看idea的运行标志,它会一直保持运行,这两个线程在互相等待对方释放自己需要的对象这样就造成了死锁,两个线程都无法继续往下执行,不但造成逻辑无法执行还浪费cpu资源;

以上代码要避免死锁,
1、可以让线程2先请求对象A再请求对象B,,即保持资源申请的有序性,这样可以同时破坏请求并持有条件和环路等待条件;

package com.dwk.thread;

/**
 * @author duweikun
 * @describe 线程死锁测试类
 * @date 2021/10/15
 */
public class DeadLockTest {

    private Object A = new Object();
    private Object B = new Object();

    public void test(){

		//两个线程请求A、B的顺序一致
		
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                synchronized (A){
                    System.out.println("线程1占用对象A");
                    synchronized (B){
                        System.out.println("线程1占用对象B");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                synchronized (A) {
                    System.out.println("线程2占用对象A");
                    Thread.sleep(1000);
                    synchronized (B) {
                        System.out.println("线程2占用对象B");
                    }
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();

    }

    public static void main(String[] args) {
        DeadLockTest deadLockTest = new DeadLockTest();
        deadLockTest.test();
    }

}

2、那么在请求另外一个对象前,先释放自己所持有的对象的锁也是可以的,即破坏请求并持有条件;

package com.dwk.thread;

/**
 * @author duweikun
 * @describe 线程死锁测试类
 * @date 2021/10/15
 */
public class DeadLockTest {

    private Object A = new Object();
    private Object B = new Object();

    public void test(){

        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                synchronized (A){
                    System.out.println("线程1占用对象A");
                    synchronized (B){
                        System.out.println("线程1占用对象B");
                        //唤醒B阻塞队列中的所有等待线程,即唤醒thread2
                        B.notifyAll();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                synchronized (B) {
                    System.out.println("线程2占用对象B");
                    //释放对象B的锁,thread2进入阻塞队列
                    B.wait();
                    synchronized (A) {
                        System.out.println("线程2占用对象A");
                    }
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();

    }

    public static void main(String[] args) {
        DeadLockTest deadLockTest = new DeadLockTest();
        deadLockTest.test();
    }

}

两种方法的执行结果如下:
在这里插入图片描述

总结:造成死锁的原因和申请资源的顺序有很大关系,使用资源申请的有序性原则就可以避免死锁,简单点说就是同步的概念,等一个用完了下一个再申请;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值