小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-15 / 0 阅读
0
0

JAVA 线程sleep和wait

“sleep是所有线程都会休息是吗?”

简短回答:不是。

sleep是让当前正在执行的线程暂停一段时间,其他线程不受影响。而 wait是用于线程间通信,它会释放锁,并让当前线程等待。

下面我们进行详细的对比和解释。


1. Thread.sleep()

  • 作用对象当前执行的线程。哪个线程调用了 sleep(),哪个线程就暂停。
  • 锁的行为:在同步代码块同步方法中调用 sleep()时,它不会释放已经持有的对象锁。
  • 唤醒条件:在指定的时间过后自动醒来,或者线程被中断(InterruptedException)。
  • 方法来源:是 Thread类的静态方法。
  • 使用场景:用来暂停当前线程的执行,不需要考虑线程间的同步问题。

示例:
假设有两个线程 Thread-A 和 Thread-B。

  • 如果 Thread-A 调用了 Thread.sleep(1000),那么只有 Thread-A 会休眠1秒钟。
  • Thread-B 仍然可以继续运行,不受任何影响。
public class SleepExample {
    public static void main(String[] args) {
        Runnable task = () -> {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " 开始工作");
            try {
                // 只有执行到这行代码的线程会休眠
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + " 结束工作");
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();
    }
}

输出可能是:

Thread-1 开始工作
Thread-2 开始工作
(等待约2秒后)
Thread-1 结束工作
Thread-2 结束工作

或者两个“结束工作”几乎同时打印,但它们各自都休眠了2秒。


2. Object.wait()

  • 作用对象:同样是当前执行的线程。但它必须在一个同步上下文中被调用。
  • 锁的行为:调用 wait()立即释放当前对象锁,这样其他线程才能获取该锁并执行。
  • 唤醒条件
    1. 其他线程调用同一个对象notify()notifyAll()方法。
    2. 指定的超时时间到期(如果使用了带超时参数的 wait(long timeout))。
    3. 线程被中断。
  • 方法来源:是 Object类的方法,任何Java对象都可以调用。
  • 使用场景:用于线程间的协作和通信,通常与 notify()/notifyAll()配合使用,实现“等待-通知”机制。

示例:

public class WaitExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("等待线程获取了锁,即将进入wait...");
                try {
                    lock.wait(); // 释放锁,并等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("等待线程被唤醒,重新获取了锁。");
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("通知线程获取了锁,准备通知...");
                lock.notify(); // 通知等待的线程
                System.out.println("通知已发出。");
                // 通知线程在退出同步块后才释放锁
            }
        });

        waitingThread.start();
        try { Thread.sleep(500); } catch (InterruptedException e) {} // 确保等待线程先执行
        notifyingThread.start();
    }
}

输出:

等待线程获取了锁,即将进入wait...
通知线程获取了锁,准备通知...
通知已发出。
等待线程被唤醒,重新获取了锁。

总结对比表格

特性 Thread.sleep() Object.wait()
作用对象 当前线程 当前线程
锁的释放 不释放任何锁 释放当前对象锁
调用方式 静态方法:Thread.sleep(millis) 实例方法:anyObject.wait()
唤醒条件 时间到期或被中断 notify/notifyAll、时间到期或被中断
所属类 Thread Object
使用前提 不需要在同步块中 必须在同步代码块或同步方法中(必须先持有锁)
用途 单纯让当前线程暂停执行 线程间通信,实现等待/通知机制

结论

所以,回到你的问题:“sleep是所有线程都会休息是吗?”

绝对不是。 sleep只会让调用它的那个当前线程休息,其他线程会继续争抢CPU时间片,正常运行。wait也是让当前线程等待,但它更复杂,涉及到锁的释放和线程间的通信。

一个简单的比喻:

  • sleep:就像你(当前线程)在工作时定了个闹钟,然后趴在桌子上小睡一会儿。你的办公桌(锁)别人还不能用,但公司的其他同事(其他线程)可以继续做他们自己的工作。
  • wait:就像你(当前线程)在等一个快递,你离开办公桌(释放锁)去休息室等着,并告诉前台(wait())。快递到了之后,前台通知你(notify()),你才能回到你的办公桌(重新获取锁)继续工作。

评论