Java多线程死锁的场景,成因和解决方案

目录

死锁:

死锁场景:

1.单线程获取一把锁:

2.两个线程获取同两把锁:

 3.多个线程获取多把锁:

 死锁成因:

死锁解决方案:


死锁:

线程执行的时候由于获取不到锁资源造成的程序卡死状态

死锁场景:

1.单线程获取一把锁:

一个线程多次(两次以上)获取同一把锁,造成死锁(前提该锁为非可重入锁)。

2.两个线程获取同两把锁:

第一个线程的锁被第二个线程持有,第二个线程的锁被第一个线程持有,造成死锁。


import java.util.concurrent.TimeUnit;

/**
 * 两个线程两把锁
 */
public class DeadLock_Demo01 {
    public static void main(String[] args) {
        Object locker1 = new Object();
        Object locker2 = new Object();
        Thread thread1 = new Thread(()->{
            System.out.println("t1申请锁资源");
            synchronized (locker1){
                System.out.println("t1获取了第一把锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker2){
                    System.out.println("t1获取了第二把锁");
                }
            }

        });
        Thread thread2 = new Thread(()->{
            System.out.println("t2申请锁资源");
            synchronized (locker2){
                System.out.println("t2获取了第二把锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (locker1){
                    System.out.println("t2获取了第一把锁");
                }
            }

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

 3.多个线程获取多把锁:

举例:有三个线程,分别只能打印A,B和C * 要求按顺序打印ABC,打印10次。思路:创建三把锁,线程1获取第一把锁,打印A成功后唤醒第二把锁,线程2获取第二把锁,打印B成功后唤醒第三把锁,线程3获取第三把锁打印C成功后唤醒第一把锁,不加干预的情况下,会陷入三个线程互相等待唤醒的死锁状态。


/**
 * 有三个线程,分别只能打印A,B和C
 * 要求按顺序打印ABC,打印10次
 * 输出示例:
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 * ABC
 */
public class FirstCode {
    public static void main(String[] args) throws InterruptedException {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Object lock3 = new Object();

        Thread threadA = new Thread(()->{
            try {
                for(int i = 0; i < 10; i++){
                    synchronized (lock1){
                        lock1.wait();
                    }
                    System.out.print("A");
                    synchronized (lock2){
                        lock2.notify();
                    }
            }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        Thread threadB = new Thread(()->{
            try {
                for(int i = 0; i < 10; i++){
                    synchronized (lock2){
                        lock2.wait();
                    }
                    System.out.print("B");
                    synchronized (lock3){
                        lock3.notify();
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        Thread threadC = new Thread(()->{
            try {
                for(int i = 0; i < 10; i++){
                    synchronized (lock3){
                        lock3.wait();
                    }
                    System.out.println("C");
                    synchronized (lock1){
                        lock1.notify();
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        threadC.start();
        threadA.start();
        threadB.start();

        //这段代码不加就造成死锁
        //Thread.sleep(1000);
        //synchronized (lock1){
        //    lock1.notify();
        //}
    }
}

 死锁成因:

1.互斥访问:线程一拿到了锁,线程二就不能同时获取同一把锁。

2.不可抢占:获取到锁的线程在自己不主动释放锁的情况下,其他线程无法抢占锁资源。

3.请求与保持:在线程一获取了一把锁后,还要继续获取第二把另外的锁。

4.循环等待:线程一等待线程二,线程二等待线程三,线程三等待线程一。

死锁解决方案:

1.互斥访问:锁特性无法打破。

2.不可抢占:锁特性无法打破。

3.请求与保持:改变获取锁的顺序。

4.循环等待:设计一套获取锁的策略,或其他方式来强制唤醒其中一个线程打破循环(如上代码末尾注释所示)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值