Blocked与Wati的区别

BLOCKED vs WAIT

简短结论先说清楚:

  • BLOCKED :线程尝试进入 synchronized 获取对象监视器(锁)但失败 时的状态 ------ 它在等待 获得锁 (并持有锁)。

  • WAITING (这里特指 Object.wait() 导致的等待):线程主动调用 wait() ,会释放锁 并进入等待队列,直到被 notify/notifyAll(或中断)唤醒,然后再去竞争锁并继续执行。

下面给你一段 Java 程序,分别演示两者的区别,并在关键时刻打印线程状态(Thread.getState())。


示例代码

java 复制代码
public class BlockedVsWaitDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== BLOCKED 演示 ===");
        blockedDemo();

        System.out.println("\n=== WAITING (wait) 演示 ===");
        waitDemo();
    }

    // 场景:一个线程持有锁并 sleep(模拟长时间占用),另一个线程尝试进入同一 synchronized -> BLOCKED
    private static void blockedDemo() throws InterruptedException {
        final Object lock = new Object();

        Thread holder = new Thread(() -> {
            synchronized (lock) {
                System.out.println("[Holder] acquired lock, going to sleep 3s");
                try { Thread.sleep(3000); } catch (InterruptedException ignored) {}
                System.out.println("[Holder] done sleeping, releasing lock");
            }
        }, "Holder");

        Thread blocker = new Thread(() -> {
            System.out.println("[Blocker] trying to enter synchronized block...");
            synchronized (lock) {
                System.out.println("[Blocker] acquired lock!");
            }
        }, "Blocker");

        holder.start();
        // 确保 holder 先占到锁
        Thread.sleep(100);

        blocker.start();
        // 等一点让 blocker 尝试获取锁,然后打印其状态
        Thread.sleep(100);
        System.out.println("[Main] Blocker state (expect BLOCKED): " + blocker.getState());

        // 等待结束
        holder.join();
        blocker.join();
    }

    // 场景:一个线程 synchronized 后调用 wait() -> 释放锁并进入 WAITING;
    // 另一个线程 synchronized 并 notify() 唤醒它。
    private static void waitDemo() throws InterruptedException {
        final Object lock = new Object();

        Thread waiter = new Thread(() -> {
            synchronized (lock) {
                System.out.println("[Waiter] acquired lock, calling wait()");
                try {
                    lock.wait(); // 释放锁,进入 WAITING
                } catch (InterruptedException e) {
                    System.out.println("[Waiter] interrupted");
                }
                System.out.println("[Waiter] resumed after wait(), continuing...");
            }
        }, "Waiter");

        Thread notifier = new Thread(() -> {
            try { Thread.sleep(500); } catch (InterruptedException ignored) {}
            synchronized (lock) {
                System.out.println("[Notifier] acquired lock, calling notify()");
                lock.notify(); // 唤醒 waiter(waiter 进入可竞争状态)
                System.out.println("[Notifier] notify done, will release lock soon");
            }
        }, "Notifier");

        waiter.start();
        // 等一点确保 waiter 已经进入 wait()
        Thread.sleep(200);
        System.out.println("[Main] Waiter state (expect WAITING): " + waiter.getState());

        notifier.start();

        // 给一些时间让 notify 执行:在 notify 之后,waiter 会变为 BLOCKED(等待重新获得锁)
        Thread.sleep(100);
        System.out.println("[Main] Waiter state maybe BLOCKED (waiting to reacquire lock): " + waiter.getState());

        waiter.join();
        notifier.join();
    }
}

预期输出(大致顺序,具体时间会有微差)

java 复制代码
=== BLOCKED 演示 ===
[Holder] acquired lock, going to sleep 3s
[Blocker] trying to enter synchronized block...
[Main] Blocker state (expect BLOCKED): BLOCKED
[Holder] done sleeping, releasing lock
[Blocker] acquired lock!

=== WAITING (wait) 演示 ===
[Waiter] acquired lock, calling wait()
[Main] Waiter state (expect WAITING): WAITING
[Notifier] acquired lock, calling notify()
[Notifier] notify done, will release lock soon
[Main] Waiter state maybe BLOCKED (waiting to reacquire lock): BLOCKED
[Waiter] resumed after wait(), continuing...

重点说明:

  • BLOCKED 演示 中,Blocker 因为 Holder 持有锁而处于 BLOCKED

  • WAITING 演示 中,当 waiter 调用 lock.wait() 后它会 释放锁并进入 WAITING 状态(因此 notifier 能拿到锁并 notify())。

    • notify() 把 waiter 从等待队列中唤醒,但 唤醒后 waiter 要先重新抢锁 ------ 在 notifier 释放锁之前,waiter 会处于 等待抢锁 的阶段,这时在 Thread.getState() 上通常看到的是 BLOCKED(因为它在等待进入 synchronized 块重新获得监视器)。一旦它成功拿到锁,状态回到 RUNNABLE 并继续执行。

总结对比(简洁版)

  • 触发方式

    • BLOCKED:线程在尝试进入 synchronized(obj) 时,目标监视器已被其他线程持有 → 进入 BLOCKED。

    • WAITING:线程主动调用 obj.wait()(或被 join() / LockSupport.park() 等) → 进入 WAITING。

  • 锁的持有情况

    • BLOCKED:没有持有锁,正在等待获取锁。

    • WAITING:调用 wait() 时会 释放锁(这是 wait 的关键行为),线程本身进入等待队列。

  • 唤醒方式

    • BLOCKED:不是被 notify 唤醒;只是当某个线程释放锁后,调度器允许它获取锁。

    • WAITING:需要 notify() / notifyAll()(或中断/超时)来唤醒,然后再去竞争锁。

  • 常见用途

    • BLOCKED:自然发生(竞争同步块)。

    • WAITING:用于线程间协作(生产者/消费者等)。

相关推荐
zhishidi2 小时前
Spring @Scheduled注解调度机制详解
java·python·spring
AAA简单玩转程序设计2 小时前
救命!Java这3个小技巧,写起来爽到飞起✨
java
IManiy2 小时前
Java表达式引擎技术选型分析(SpEL、QLExpress)
java·开发语言
历程里程碑2 小时前
C++ 17异常处理:高效捕获与精准修复
java·c语言·开发语言·jvm·c++
雨雨雨雨雨别下啦2 小时前
ssm复习总结
java·开发语言
速易达网络2 小时前
基于Java Servlet的用户登录系统设计与实现
java·前端·mvc
拾贰_C2 小时前
【python | pytorch | 】.报错怎么找到问题所在?
开发语言·pytorch·python
散一世繁华,颠半世琉璃3 小时前
从 0 到 1 优化 Java 系统:方法论 + 工具 + 案例全解析
java·性能优化·操作系统
JasmineWr3 小时前
Java SPI和OSGi
java·开发语言