11-死锁

目录

1.死锁定义

1.1.代码演示

1.2.使用jconsole/jvisualvm/jmc查看死锁

①使用jconsole:最简单。

②使用jvisualvm:(Java虚拟机)更方便,更直观,更智能,更高级,是合适的选择。

③使用jmc:加载的资源更多,需要的时间更长,最高级。

2.死锁产生原因

①互斥条件

②不可被剥夺条件

③请求并持有条件

④环路等待条件

3.如何解决死锁问题?

解决死锁方案1:破环请求并持有条件

解决死锁方案2:破坏环路等待条件/使用顺序锁


1.死锁定义

死锁是指两个或两个以上的执行单元(进程/线程/协程(Java中没有协程的概念)在执⾏过程中,由于竞争资源或者由于彼此通信⽽造成的⼀种阻塞的现象,若⽆外⼒作⽤,它们都将⽆法推进下去。

也就是两个进程/线程/协程拥有锁的情况下,⼜在尝试获取对⽅锁,从⽽造成程序⼀直阻塞的情况。

一个线程可以拥有多把锁,但一把锁同一时间只能被一个线程所占用。

1.1.代码演示

import java.util.concurrent.TimeUnit;

/**
 * 死锁示例
 */
public class Thread18 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            //1.占有一把锁(锁A)
            synchronized (lockA){
                System.out.println("线程1:获得锁A");
                //因为线程的执行是不可控的。中间设置空档期,休眠1s,让线程2有时间先占有锁B(线程1得到锁B的速度不能大于线程2得到锁B的速度)
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //2.尝试获取线程2的锁B
                synchronized (lockB){
                    System.out.println("线程1:获得锁B");
                }
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
           //1.占有一把锁(锁B)
            synchronized (lockB){
                System.out.println("线程2:获得锁B");
                //休眠1s(保证线程1有充足的时间得到锁A)
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //2.尝试获取线程1的锁A
                synchronized (lockA){
                    System.out.println("线程2:获得锁A");
                }
            }
        });
        t2.start();
    }
}

1.2.使用jconsole/jvisualvm/jmc查看死锁

①使用jconsole:最简单。

②使用jvisualvm:(Java虚拟机)更方便,更直观,更智能,更高级,是合适的选择。

都在同一级目录。

③使用jmc:加载的资源更多,需要的时间更长,最高级。

2.死锁产生原因

①互斥条件

⼀个资源(锁)同一时间只能被⼀个线程占有,当这个资源被占⽤之后其他线程就只能等待。

②不可被剥夺条件

当⼀个线程不主动释放资源时,此资源⼀直被拥有线程占有。

③请求并持有条件

线程已经拥有了⼀个资源之后,又尝试请求新的资源。

④环路等待条件

产⽣死锁⼀定是发⽣了线程资源环形链。

这四个因素(缺一不可)共同导致了死锁。

3.如何解决死锁问题?

改变死锁中的任意⼀个或多个条件就可以解决死锁的问题,其中可以被修改的条件只有后两个:请求并持有条件环路等待条件(人为控制,可被打破,可被修改);前两个条件都是系统设定的。

解决死锁方案1:破环请求并持有条件

import java.util.concurrent.TimeUnit;

/**
 * 解决死锁方案:破环请求并持有条件
 */
public class UnDeadLock1 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() ->{
            synchronized (lockA){
                System.out.println("线程1:得到了锁A");
                //业务代码...
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
//                synchronized (lockB){
//                    System.out.println("线程1:得到了锁B");
//                    //业务代码...
//                    System.out.println("线程1:释放了锁B");
//                }
                System.out.println("线程1:释放了锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() ->{
            synchronized (lockB){
                System.out.println("线程2:得到了锁B");
                //业务代码...
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
//                synchronized (lockA){
//                    System.out.println("线程2:得到了锁A");
//                    //业务代码...
//                    System.out.println("线程2:释放了锁A");
//                }
                System.out.println("线程2:释放了锁B");
            }
        },"线程2");
        t2.start();
    }
}

解决死锁方案2:破坏环路等待条件/使用顺序锁

import java.util.concurrent.TimeUnit;

/**
 * 解决死锁方案:破坏环路等待条件
 */
public class UnDeadLock2 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() ->{
            synchronized (lockA){
                System.out.println("线程1:得到了锁A");
                //业务代码...
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
                synchronized (lockB){
                    System.out.println("线程1:得到了锁B");
                    //业务代码...
                    System.out.println("线程1:释放了锁B");
                }
                System.out.println("线程1:释放了锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() ->{
            synchronized (lockA){
                System.out.println("线程2:得到了锁A");
                //业务代码...
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
                synchronized (lockB){
                    System.out.println("线程2:得到了锁B");
                    //业务代码...
                    System.out.println("线程2:释放了锁B");
                }
                System.out.println("线程2:释放了锁A");
            }
        },"线程2");
        t2.start();
    }
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值