java中sleep与wait的区别

发布于:2025-08-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

在 Java 中,sleep()wait()都用于线程控制,但它们的使用场景、工作机制和功能有本质区别,主要体现在以下几个方面:

1. 所属类不同

  • sleep()java.lang.Thread类的静态方法,通过Thread.sleep()调用。
  • wait()java.lang.Object类的实例方法,必须通过对象实例调用(如obj.wait())。

2. 对锁的影响不同

这是两者最核心的区别:

  • sleep()不会释放锁
    当线程执行sleep()时,会暂停执行指定时间,但持有当前对象的锁不会释放。其他线程无法获取该锁,只能等待sleep()结束后线程继续执行。

  • wait()会释放锁
    当线程执行wait()时,会释放当前对象的锁,并进入该对象的等待队列(waiting pool)。其他线程可以获取该锁并执行同步代码块,直到被notify()/notifyAll()唤醒。

3. 使用场景不同

  • sleep()用于暂停执行
    通常用于控制线程执行的时间间隔,让线程 “休眠” 一段时间后自动恢复,不依赖其他线程的通知。
    示例:

    try {
        // 线程休眠1秒,不释放锁
        Thread.sleep(1000); 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
  • wait()用于线程间通信
    通常用于线程间的协作,让线程等待某个条件满足(如资源就绪),需其他线程调用notify()/notifyAll()唤醒。
    示例:

    synchronized (obj) {
        try {
            // 释放obj的锁,进入等待队列
            obj.wait(); 
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

4. 唤醒方式不同

  • sleep()自动唤醒
    只需等待指定时间结束,线程会自动从阻塞状态恢复到就绪状态。

  • wait()需主动唤醒
    必须由其他线程调用同一对象notify()(唤醒一个等待线程)或notifyAll()(唤醒所有等待线程)才能恢复。若未被唤醒,线程会一直处于等待状态。
    此外,wait(long timeout)也支持超时自动唤醒(类似sleep()的时间参数)。

5. 调用前提不同

  • sleep()可在任何地方调用
    无需在同步代码块(synchronized)中使用,即使在非同步环境下也能正常工作。

  • wait()必须在同步环境中调用
    必须在synchronized代码块或方法中调用,否则会抛出IllegalMonitorStateException。因为wait()需要释放对象锁,而只有持有锁的线程才能释放锁。

6. 异常处理

两者都会抛出InterruptedException(受检异常),必须捕获或声明抛出。该异常在线程休眠 / 等待时被中断(如其他线程调用interrupt())时触发。

总结对比表

特性 sleep() wait()
所属类 Thread(静态方法) Object(实例方法)
锁释放 不释放锁 释放锁
使用场景 控制执行间隔 线程间通信(等待 / 唤醒)
唤醒方式 时间到自动唤醒 notify()/notifyAll()或超时
调用前提 无需同步环境 必须在synchronized中调用

典型使用示例

sleep()示例(不释放锁)
public class SleepDemo {
    public static void main(String[] args) {
        Object lock = new Object();
        
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("线程1获取锁,开始执行");
                try {
                    // 休眠2秒,不释放lock锁
                    Thread.sleep(2000); 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1执行完毕");
            }
        }).start();
        
        new Thread(() -> {
            synchronized (lock) {
                // 需等待线程1释放锁后才能执行
                System.out.println("线程2获取锁,开始执行");
            }
        }).start();
    }
}

输出:

线程1获取锁,开始执行
(等待2秒)
线程1执行完毕
线程2获取锁,开始执行
wait()示例(释放锁)
public class WaitDemo {
    public static void main(String[] args) {
        Object lock = new Object();
        
        // 等待线程
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("等待线程:获取锁,开始等待");
                try {
                    // 释放lock锁,进入等待队列
                    lock.wait(); 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("等待线程:被唤醒,继续执行");
            }
        }).start();
        
        // 唤醒线程
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 确保等待线程先执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock) {
                System.out.println("唤醒线程:获取锁,准备唤醒");
                lock.notify(); // 唤醒等待线程
                System.out.println("唤醒线程:执行完毕");
            }
        }).start();
    }
}

输出:

等待线程:获取锁,开始等待
(等待1秒)
唤醒线程:获取锁,准备唤醒
唤醒线程:执行完毕
等待线程:被唤醒,继续执行

总之,sleep()是线程自身的休眠,不涉及锁的释放;wait()是线程间的协作机制,必须配合锁和唤醒操作使用,核心是释放锁并等待通知。