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

相关推荐
2301_790300965 小时前
C++与微服务架构
开发语言·c++·算法
独断万古他化5 小时前
【Spring 核心:AOP】基础到深入:思想、实现方式、切点表达式与自定义注解全梳理
java·spring·spring aop·aop·切面编程
一切尽在,你来5 小时前
C++多线程教程-1.1.4 并发编程的风险(竞态条件、死锁、数据竞争、资源争用)
开发语言·c++
艳阳天_.5 小时前
web 分录科目实现辅助账
开发语言·前端·javascript
梵刹古音5 小时前
【C语言】 循环结构
c语言·开发语言·算法
消失的旧时光-19435 小时前
C++ 函数参数传递方式总结:什么时候用值传递、引用、const 引用?
开发语言·c++
2601_949868365 小时前
Flutter for OpenHarmony 剧本杀组队App实战04:发起组队表单实现
开发语言·javascript·flutter
一匹电信狗5 小时前
【C++】CPU的局部性原理
开发语言·c++·系统架构·学习笔记·c++11·智能指针·新特性
编程彩机5 小时前
互联网大厂Java面试:从分布式事务到微服务优化的技术场景解读
java·spring boot·redis·微服务·面试·kafka·分布式事务
bbq粉刷匠5 小时前
Java-排序2
java·数据结构·排序算法