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

相关推荐
陈小桔几秒前
logging模块-python
开发语言·python
消失的旧时光-19431 分钟前
函数指针 + 结构体 = C 语言的“对象模型”?——从 C 到 C++ / Java 的本质统一
linux·c语言·开发语言·c++·c
!停2 分钟前
C语言栈和队列的实现
开发语言·数据结构
xiaobaishuoAI2 分钟前
后端工程化实战指南:从规范到自动化,打造高效协作体系
java·大数据·运维·人工智能·maven·devops·geo
源代码•宸3 分钟前
Golang语法进阶(定时器)
开发语言·经验分享·后端·算法·golang·timer·ticker
期待のcode5 分钟前
TransactionManager
java·开发语言·spring boot
郝学胜-神的一滴5 分钟前
Linux系统编程:深入理解读写锁的原理与应用
linux·服务器·开发语言·c++·程序人生
Larry_Yanan6 分钟前
Qt多进程(十一)Linux下socket通信
linux·开发语言·c++·qt
Hello.Reader6 分钟前
PyFlink JAR、Python 包、requirements、虚拟环境、模型文件,远程集群怎么一次搞定?
java·python·jar
计算机学姐7 分钟前
基于SpringBoot的汽车租赁系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·spring·汽车·推荐算法