• JAVA并发编程--7 在编程过程中怎么避免死锁


    前言:多个线程去抢占两个或两个以上的共享资源,共享资源同一时间只能被一个线程所持有;线程之间相互等待其他线程进行锁的释放;导致程序无法往下执行。

    1 死锁发生的条件:
    互斥:共享资源X和Y ,只能被一个线程占有;
    占有且等待:线程T1已经获取共享资源X,在等待获取共享资源Y 的时候,不释放共享资源X;
    不可抢占:其他线程不能强行抢占线程T1占有共享资源X;
    循环等待:线程T1等待线程T2占有的共享资源,线程T2等待线程T1占有的共享资源;

    一旦出现上述条件,就有死锁产生的可能;
    2 避免死锁:
    互斥和不可抢占的条件不能被破坏;占有且等待:如果在获取不到其他资源锁的时候就释放掉已获取的锁,可以进行业务处理;循环等待:可以在业务上顺序加锁来避免;
    2.1 扩大锁:
    2.1.1 将要获取的资源放入到一个集合中,每次线程在获取锁的时候,只要集合中改资源的锁已经被抢占,则不允许其他线程获取锁:

    package org.lgx.bluegrass.bluegrasscoree.util.deadlockdemo;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Description TODO
     * @Date 2022/11/2 09:10
     * @Author lgx
     * @Version 1.0
     */
    public class LockSource {
    
        private static volatile List lockRes = new ArrayList();
        private static volatile Thread exclusiveOwnerThread;
    
        /**
         * 立即尝试去获取一次锁
         *
         * @param lockRes1
         * @return
         */
        public synchronized boolean getLockResourceAtOnce(String... lockRes1) {
            for (int i = 0; i < lockRes1.length; i++) {
                if (lockRes.contains(lockRes1[i])) {
                    return false;
                }
            }
    
            // get lock
            for (int i = 0; i < lockRes1.length; i++) {
                lockRes.add(lockRes1[i]);
            }
            exclusiveOwnerThread = Thread.currentThread();
            return true;
    
        }
    
        /**
         * 释放锁
         *
         * @param lockRes1
         */
        public synchronized void releaseLockResource(String... lockRes1) {
            if (exclusiveOwnerThread.getId() != Thread.currentThread().getId()) {
                // 非法释放
                throw new IllegalMonitorStateException();
            }
            for (int i = 0; i < lockRes1.length; i++) {
                lockRes.remove(lockRes1[i]);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.1.2 获取锁:

    package org.lgx.bluegrass.bluegrasscoree.util.deadlockdemo;
    
    import lombok.Data;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    
    /**
     * @Description TODO
     * @Date 2022/10/27 15:58
     * @Author lgx
     * @Version 1.0
     */
    @Data
    public class DeadLockDemo {
        static volatile List locks = new ArrayList(10);
    
    
        // private String uuid;
        final static String lockstr1 = "str1";
        final static String lockstr2 = "str2";
    
        private static int num = 0;
    
    
        public static void main(String[] args) throws InterruptedException {
            DeadLockDemo deadLockDemo = new DeadLockDemo();
            LockSource lockSource = new LockSource();
            CountDownLatch countDownLatch = new CountDownLatch(2000);
            for (int i = 0; i < 1000; i++) {
                Thread t = new Thread(() -> {
                    countDownLatch.countDown();
                    for (; ; ) {
                        if (lockSource.getLockResourceAtOnce(lockstr1, lockstr2)) {
                            deadLockDemo.todoSomeThing();
                            lockSource.releaseLockResource(lockstr1, lockstr2);
                            break;
                        }
                    }
                }, "t" + i);
                t.start();
            }
            countDownLatch.await();
    
            System.out.println("num = " + num);
    
    
        }
    
        private synchronized void todoSomeThing() {
            // 顺序获取
            synchronized (lockstr1) {
                synchronized (lockstr2) {
                    // get lock and do some thing
                    num += 1;
                    System.out.println("num = " + num);
                }
            }
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.2 打破不可抢占:
    synchronized 在获取不到锁时,会一直等待下去,无法被中断;此时可以使用lock,使用
    Lock.tryLock() 进行获取锁,只用获取到锁的时候才进行业务处理;

    2.3 打破循环等待:将锁按照一定的顺序进行排序后,然后依次访问临界资源
    在这里插入图片描述

    3 总结:
    死锁的产生基本上都是因为业务中对于获取锁和释放锁不规范造成的;所以就需要我们在获取锁资源的时候尽可能一次性获取锁资源,或者保证顺序加锁,在业务完成时,使用的是需要手动释放锁的记得对锁进行释放。

  • 相关阅读:
    前端刷新token,判断token是否过期(jwt鉴权)
    【自动驾驶】欧拉角和旋转矩阵之间的转换
    SOLIDWORKS 2024 Electrical全新升级
    maven引入kabeja依赖
    python curl2pyreqs 生成接口脚本
    什么商业模式是适合你,元宇宙电商NFG了解一下
    Java中为什么wait和notify方法要在同步块中调用
    卡片层叠Banner
    (leetcode)二叉树最大深度
    Android Media Framework(三)OpenMAX API阅读与分析
  • 原文地址:https://blog.csdn.net/l123lgx/article/details/127553181