在 Java 中,wait 和 sleep 都用于让线程进入等待状态,但它们在同步操作和线程管理方面有显著区别。以下是它们的主要区别:
1. 所属的类
- wait是- Object类的方法。
- sleep是- Thread类的静态方法。
2. 使用场景
- wait用于线程间通信,它通常在同步代码块或同步方法中使用,以便让当前线程等待,直到另外一个线程调用同一对象的- notify或- notifyAll方法。
- sleep用于让当前线程暂停执行一段时间,通常用于控制线程的执行节奏或模拟延迟。
3. 锁的释放
- wait会释放当前线程持有的对象锁,这样其他线程可以获得这个锁并继续执行。
- sleep不会释放当前线程持有的任何锁。线程在休眠期间依然持有锁,其他线程无法获得该锁。
4. 重新唤醒
- wait需要其他线程调用同一对象的- notify或- notifyAll方法来唤醒。
- sleep在指定的时间段结束后自动唤醒。
5. 使用位置
- wait必须在同步代码块或同步方法中使用,否则会抛出- IllegalMonitorStateException。
- sleep可以在任何地方使用,不需要同步块或同步方法。
关于锁的释放,举个下面的代码例子:
package chapter01;
class Test {
    public static void main(String[] args) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
class WaitNotifyExample {
    private final Object lock = new Object();
    public void waitingMethod() {
        synchronized (lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " is waiting...");
                lock.wait();
                System.out.println(Thread.currentThread().getName() + " is resumed.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void notifyingMethod() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " is notifying...");
            lock.notify();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        WaitNotifyExample example = new WaitNotifyExample();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                example.waitingMethod();
            }
        }, "Thread-1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                example.notifyingMethod();
            }
        }, "Thread-2");
        t1.start();
        Thread.sleep(1000); // Ensure t1 starts and calls wait
        t2.start();
    }
}

wait 和 notify 示例
- WaitNotifyExample 类包含两个方法:waitingMethod 和 notifyingMethod。
- waitingMethod 在同步代码块中调用 wait 方法,使当前的线程1等待并释放锁lock。
- 因为释放了锁lock,所以线程2能够在 notifyingMethod 方法中进入同步代码块中调用 notify 方法,唤醒等待的线程。
- 在 main 方法中,两个线程 t1 和 t2 分别调用 waitingMethod 和 notifyingMethod,演示线程间的通信。
与之对比,sleep方法则不会让线程释放掉当前持有的锁
class SleepExample {
    private final Object lock = new Object();
    public void sleepMethod() {
        synchronized (lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " got the lock and is sleeping...");
                Thread.sleep(2000); // Sleep for 2 seconds
                System.out.println(Thread.currentThread().getName() + " woke up and is releasing the lock.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void anotherMethod() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " got the lock and is doing work.");
        }
    }
    public static void main(String[] args) {
        SleepExample example = new SleepExample();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                example.sleepMethod();
            }
        }, "Thread-1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                example.anotherMethod();
            }
        }, "Thread-2");
        t1.start();
        try {
            Thread.sleep(500); // Ensure t1 starts and gets the lock
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }
}

可以发现线程1得到了锁,然后调用了sleep,但是这时候并没有释放掉锁lock,所以线程2必须等到线程1睡醒了执行完代码然后释放锁lock才能进入 anotherMethod 的 synchronized 的同步代码块。



















