Java多线程中的死锁与饥饿区别解析

使用 GPT-4o-mini 回答Java Q&A Hub

問題:

Java面试题之多线程 死锁与饥饿的区别?

答案:

在Java多线程编程中,死锁和饥饿是两种常见的问题,它们虽然都与线程的执行有关,但有着本质的区别。

死锁(Deadlock)

定义:死锁是指两个或多个线程在执行过程中,因为争夺资源而造成的一种互相等待的状态。此时,所有线程都在等待对方释放资源,导致程序无法继续执行。

特征

  1. 互斥:至少有一个资源是以非共享的方式占用的,即某个线程持有资源时,其他线程不能使用。
  2. 持有并等待:一个线程持有至少一个资源,并等待获取其他线程持有的资源。
  3. 不剥夺:已经分配给线程的资源在未使用完之前,不能被其他线程强行剥夺。
  4. 循环等待:存在一种线程资源的循环等待关系。

示例

class A {
    synchronized void methodA(B b) {
        System.out.println("Thread 1: Holding A...");
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        System.out.println("Thread 1: Waiting for B...");
        b.last();
    }
}

class B {
    synchronized void last() {
        System.out.println("Thread 2: Holding B...");
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        System.out.println("Thread 2: Waiting for A...");
    }
}

在这个例子中,线程1持有A并等待B,而线程2持有B并等待A,导致死锁。

饥饿(Starvation)

定义:饥饿是指某个线程由于资源分配策略的原因,长时间得不到所需的资源,导致无法执行。饥饿通常是由于优先级调度不当或资源分配不均造成的。

特征

  1. 线程在等待资源时,可能会被其他高优先级的线程不断抢占,导致其长时间得不到执行。
  2. 饥饿并不一定会导致程序完全停止,但会导致某些线程无法得到执行机会。

示例

class HighPriorityThread extends Thread {
    public void run() {
        while (true) {
            // 执行某些高优先级的任务
        }
    }
}

class LowPriorityThread extends Thread {
    public void run() {
        while (true) {
            // 执行某些低优先级的任务
        }
    }
}

在这个例子中,如果高优先级线程一直在运行,低优先级线程可能会长时间得不到执行机会,从而导致饥饿。

总结

  • 死锁是多个线程互相等待,导致程序无法继续执行。
  • 饥饿是某个线程长时间得不到资源,无法执行,但其他线程仍然在运行。

理解这两者的区别对于编写高效且健壮的多线程程序至关重要。