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:用于线程间协作(生产者/消费者等)。

相关推荐
小羊没烦恼!7 小时前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里8 小时前
java中的继承和多态的区别
java
小羊没烦恼!8 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕8 小时前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码8 小时前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖8 小时前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时8 小时前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读9 小时前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang9 小时前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
C语言小火车9 小时前
C/C++ 为什么需要编译器?
开发语言·c++