理解 Java 线程的 Blocked 和 Wait 状态

在并发编程中,线程是执行程序的基本单位。Java 提供了丰富的线程管理工具来处理并发问题。当我们在使用多线程的过程中,常常会遇到线程处于不同状态的情况。在这一篇文章中,我们将重点讨论 Java 线程的 BlockedWait 状态,并且通过代码示例来加深理解。

线程状态概述

Java 线程有几种主要状态:

  • New: 线程被创建,但还未调用 start() 方法。
  • Runnable: 线程可以运行,或者正在运行。
  • Blocked: 线程由于正在等待某个对象的监视器锁而被阻塞。
  • Waiting: 线程在等待其他线程的特定操作(如 join()wait()),并不占用 CPU 资源。
  • Timed Waiting: 线程等待某个操作的结束,但有一个时间限制(如 sleep()wait(timeout))。
  • Terminated: 线程执行完毕,或因异常导致终止。

Blocked 状态

Blocked 状态的产生

当两个或多个线程竞争同一个监视器锁时,如果一个线程持有锁,其他线程就会被阻塞,直至持锁线程释放该锁。此状态下,线程无法继续执行,直到获得锁。

Blocked 示例代码

以下示例演示了线程如何因竞争锁而进入 Blocked 状态:

public class BlockedExample {
    public static void main(String[] args) {
        final Object lock = new Object();
        
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1: Holding lock...");
                try {
                    // 线程持有锁并阻塞一段时间
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            // thread2 尝试获取相同的锁
            synchronized (lock) {
                System.out.println("Thread 2: Acquired lock!");
            }
        });

        thread1.start();
        thread2.start();
    }
}

在这个示例中,Thread 1 持有 lock 的监视器锁,Thread 2 则必须等待,直到 Thread 1 释放锁。在此期间,Thread 2 将处于 Blocked 状态。

Wait 状态

Wait 状态的产生

当线程调用 Object.wait() 方法时,它会放弃锁并进入 Wait 状态。这意味着它将被挂起,直到其他线程调用 notify()notifyAll() 方法来唤醒它。

Wait 示例代码

以下示例演示了线程如何进入 Wait 状态:

public class WaitExample {
    public static void main(String[] args) {
        final Object lock = new Object();
        
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1: Holding lock and waiting...");
                try {
                    lock.wait(); // 进入待等待状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1: Resumed!");
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2: Holding lock and notifying...");
                lock.notify(); // 唤醒等待的线程
            }
        });

        thread1.start();
        // 确保 thread1 先获取锁并进入等待状态
        try {
            Thread.sleep(100); // 确保 thread1 能首先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();
    }
}

在这个示例中,Thread 1 在获取 lock 的监视器锁后,调用了 wait() 方法,此时它进入 Wait 状态,直到 Thread 2 调用 notify() 进行唤醒。

流程图

以下是描述线程状态流转的流程图:

flowchart TD
    A[New] -->|start()| B[Runnable]
    B -->|run()| C[Blocked]
    C -->|lock released| B
    B -->|wait()| D[Waiting]
    D -->|notify()| B
    B -->|notifyAll()| B
    B -->|finished| E[Terminated]

线程调度的甘特图

以下是一个简单的甘特图,用以描述线程调度:

gantt
    title Thread Scheduling Example
    dateFormat  YYYY-MM-DD
    section Thread1
    Blocked         :a1, 2023-10-01, 2d
    Waiting         :after a1  , 2d
    section Thread2
    Running         :a2, 2023-10-02, 2d

结论

在 Java 的多线程编程中,理解线程的 Blocked 状态与 Wait 状态十分重要。它们涉及至关重要的线程同步和资源竞争问题。合理地管理线程状态,不仅可以提升程序效率,还可以避免潜在的死锁和资源浪费。通过示例代码和流程图,我们希望你能更好地理解这些概念。希望这篇文章能为你的 Java 多线程编程之旅带来帮助!