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;

public class LockSource {

    private static volatile List lockRes = new ArrayList();
    private static volatile Thread exclusiveOwnerThread;

    public synchronized boolean getLockResourceAtOnce(String... lockRes1) {
        for (int i = 0; i < lockRes1.length; i++) {
            if (lockRes.contains(lockRes1[i])) {
                return false;
            }
        }

        for (int i = 0; i < lockRes1.length; i++) {
            lockRes.add(lockRes1[i]);
        }
        exclusiveOwnerThread = Thread.currentThread();
        return true;

    }

    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]);
        }
    }
}

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;

@Data
public class DeadLockDemo {
    static volatile List locks = new ArrayList(10);

    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) {

                num += 1;
                System.out.println("num = " + num);
            }
        }

    }

}

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

2.3 打破循环等待:将锁按照一定的顺序进行排序后,然后依次访问临界资源

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

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

Original: https://blog.csdn.net/l123lgx/article/details/127553181
Author: 拽着尾巴的鱼儿
Title: JAVA并发编程–7 在编程过程中怎么避免死锁

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/658078/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球