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

相关推荐
rannn_1117 分钟前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
杜子不疼.10 分钟前
PyPTO:面向NPU的高效并行张量编程范式
开发语言
qq_124987075310 分钟前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
lly20240611 分钟前
C# 结构体(Struct)
开发语言
短剑重铸之日17 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
YMWM_21 分钟前
python3继承使用
开发语言·python
Once_day37 分钟前
C++之《程序员自我修养》读书总结(1)
c语言·开发语言·c++·程序员自我修养
若鱼191939 分钟前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王1 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法