关于 Java 中的死锁

ouyu69 发布于 12 天前 8 次阅读


什么是死锁

多个进程或者线程同时被被阻塞,他们中的一个或者全部都在等待某个资源的释放。但是由于进程或者线程被无限期的阻塞,导致程序不能正常终止。

产生死锁的四个必要条件

  1. 互斥:资源必须处于非共享模式,即一次只能由一个线程可以使用,如果另一线程申请资源,就必须等待直到该资源被释放为止。
  2. 占有并等待:一个进程应该至少占用一个资源,并等待另一资源,但是该资源被其他线程所占用。
  3. 非抢占:资源不能被抢占。只能在持有资源的线程完成任务后,该资源才会被释放。
  4. 循环等待:有一组等待进程 ${P_0,P_1,...,P_n}$ ,$P_0$ 等待的资源被 $P_1$占用,$P_1$ 等待的资源被 $P_2$占用,一次类推,形成了一个环。

锁顺序死锁

线程 1 拿到 A锁 后 又去拿 B锁,线程 2 拿到 B锁 后 又去拿 A锁

导致线程 1 拿B锁的时候,B锁被 线程 2 拿着,线程1阻塞
线程 2 拿A锁的时候,A锁 被 线程 1 拿着,线程2阻塞
最终两个线程谁也拿不到,使得两个线程都开始阻塞

public void test2() throws InterruptedException {
    Object lock = new Object();
    Object lockA = new Object();
    Object lockB = new Object();

    Thread thread1 = new Thread(()->{
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName() +"获取 A" );
            try{
                Thread.sleep(100);
            }catch (Exception e){
                e.printStackTrace();
            }
            synchronized (lockB){
                System.out.println(Thread.currentThread().getName() +"获取 B" );

            }
        }
    },"线程1");
    Thread thread2 = new Thread(()->{
        synchronized (lockB){
            System.out.println(Thread.currentThread().getName() +"获取 B" );
            try{
                Thread.sleep(100);
            }catch (Exception e){
                e.printStackTrace();
            }
            synchronized (lockA){
                System.out.println(Thread.currentThread().getName() +"获取 A" );

            }
        }
    },"线程2");
    thread1.start();
    thread2.start();
    thread1.join();
    thread2.join();
}

不可重入锁 造成的死锁

对于不可重入锁,如果在一个线程里重复地获取它,就会造成死锁,因为使用该锁需要等待当前线程释放锁,但想要释放锁就必须要获取锁,造成阻塞。

public void test2() throws InterruptedException {
    NonReentrantLock lock1 = new NonReentrantLock();

    Thread thread1 = new Thread(()->{
        try {
            lock1.lock();
            System.out.println(Thread.currentThread().getName() +"获取 A" );
            try{
                lock1.lock();
                System.out.println(Thread.currentThread().getName() +"获取 A+" );
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock1.unlock();
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            lock1.unlock();
        }
    },"线程1");
    thread1.start();
    thread1.join();
}
package utils;

/**
 * @Date 2025-11-23 23:08
 * @Author ouyu
 * @Description
 **/
public class NonReentrantLock {
    private boolean isLocked = false;

    public synchronized void lock() throws InterruptedException {
        while (isLocked) {
            wait(); // 如果锁已被持有,当前线程等待
        }
        isLocked = true; // 获取锁
    }

    public synchronized void unlock() {
        isLocked = false; // 释放锁
        notify(); // 唤醒等待的线程
    }
}
我打算法竞赛,真的假的。
最后更新于 2025-11-23