死锁

死锁概念

多个线程互相占用着对方需要的资源:线程A持有R1的锁,并等待R2的锁;线程B持有R2的锁,并等待R1的锁!

public class DeadLock {
    private final Object MUTEX_READ = new Object();
    private final Object MUTEX_WRITE = new Object();

    public void read() {
        synchronized (MUTEX_READ) {
            System.out.println(Thread.currentThread().getName() + " get READ lock !");

            synchronized (MUTEX_WRITE) {
                System.out.println(Thread.currentThread().getName() + " get Write lock !");
            }
            System.out.println(Thread.currentThread().getName() + " release Write lock !");
        }
        System.out.println(Thread.currentThread().getName() + " release READ lock !");
    }

    public void write() {
        synchronized (MUTEX_WRITE) {
            System.out.println(Thread.currentThread().getName() + " get Write lock !");

            synchronized (MUTEX_READ) {
                System.out.println(Thread.currentThread().getName() + " get READ lock !");
            }
            System.out.println(Thread.currentThread().getName() + " release READ lock !");
        }
        System.out.println(Thread.currentThread().getName() + " release Write lock !");
    }

    public static void main(String[] args) {
        final DeadLock deadLock = new DeadLock();
        new Thread(
                () -> {
                    while (true) {
                        deadLock.read();
                    }
                }, "READ-THREAD"
        ).start();

        new Thread(
                () -> {
                    while (true) {
                        deadLock.write();
                    }
                }, "WRITE-THREAD"
        ).start();
    }
}

输出结果:

READ-THREAD get READ lock !
WRITE-THREAD get Write lock !
// ... 程序无法退出

JDK中HashMap不是线程安全的类,如果在多线程同时写操作的情况下不对其进行同步化封装,则很容易出现死循环引起的死锁!

HashMap不具备线程安全的能力,如果想要使用线程安全的map结构请使用ConcurrentHashMap或者使用Collections.synchronizedMap来代替。

死锁需要满足的条件

死锁的四个必要条件:

互斥:进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

请求和保持:进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。(要想破坏请求和保持条件,就要一次性拿到所有资源。)

不可剥夺进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。(破坏不可剥夺条件:为了解决内置锁的执着,Java 显示锁支持通知(notify/notifyall)和等待(wait))——不可重入锁会出现死锁情况!

环路等待:在发生死锁时,必然存在一个进程—资源的环形链,即进程集合{P1,P2,···,Pn}中的 P1 正在等待一个 P2 占用的资源;P2 正在等待 P3 占用的资源,……,Pn 正在等待已被 P0 占用的资源。(破坏环路等待——只需要将资源序号大小排序获取)

posted @ 2021-03-14 17:56  chenzufeng  阅读(52)  评论(0编辑  收藏  举报