Java中wait()与sleep()方法的不同点是什么?

Java 多线程开发中,wait()和sleep()极易被混淆,二者底层机制差别巨大。本文分别讲解 wait() 属于 Object 成员方法、休眠释放锁,sleep() 是 Thread 静态方法、休眠不释放锁的核心原理,搭配代码示例对比用法,结合生产者‑消费者模型介绍实际场景,同时梳理使用规范以及死锁等安全隐患。
wait() 方法的工作原理
wait() 方法是 Object 类中的一个方法,它用于使当前线程进入等待状态。调用 wait() 的线程会进入一个阻塞状态,直到其他线程调用同一个对象的 notify() 或 notifyAll() 方法来唤醒它。需要注意的是,wait() 方法必须在 同步代码块 或 同步方法 中调用,因为它会释放对象的锁。
wait() 方法的关键特性
- 释放锁:调用
wait()后,当前线程释放它所持有的锁,这样其他线程可以进入该同步块。 - 阻塞线程:线程在调用
wait()后会进入阻塞状态,直到被唤醒。 - 条件判断:
wait()常常与条件判断一起使用,以便线程可以在等待时判断某些条件是否满足。
wait() 的使用示例
public class WaitExample {
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread1: Waiting...");
lock.wait(); // 进入等待状态并释放锁
System.out.println("Thread1: Resumed.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread2: Performing task...");
lock.notify(); // 唤醒正在等待的线程
System.out.println("Thread2: Task completed.");
}
});
thread1.start();
Thread.sleep(1000); // 确保 thread1 先执行并进入等待
thread2.start();
}
}
在这个例子中,thread1 调用 wait() 进入等待状态,释放锁。thread2 调用 notify() 唤醒 thread1,然后 thread1 继续执行。
sleep() 方法的工作原理
sleep() 方法是 Thread 类中的一个静态方法,它使当前线程暂停执行指定的时间,而不会释放持有的锁。线程在指定的时间内进入休眠状态,时间到后会自动恢复执行。sleep() 方法通常用于暂停线程的执行,而不涉及线程间的协调或通信。
sleep() 方法的关键特性
- 不释放锁:与
wait()不同,调用sleep()后,当前线程不会释放它持有的锁,这意味着其他线程无法获取该锁,直到当前线程恢复执行。 - 线程休眠:线程进入睡眠状态,等待指定时间后自动唤醒继续执行。
- 常用场景:
sleep()通常用于控制线程的执行时间,比如模拟延迟、定时任务等场景。
sleep() 的使用示例
public class SleepExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
System.out.println("Thread: Sleeping...");
Thread.sleep(2000); // 使线程休眠 2 秒
System.out.println("Thread: Woke up after sleep.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
thread.start();
}
}
在这个例子中,thread 线程调用 sleep(2000) 使自己暂停 2 秒。线程不会释放锁,它会在 2 秒后恢复执行。
知识拓展
wait() 和 sleep() 的应用场景
- wait() 的场景:
wait()主要用于 线程间的通信,在多个线程之间协调执行顺序。例如,在生产者-消费者模式中,生产者线程可以在资源不足时调用wait(),消费者线程可以在有新资源时调用notify()唤醒生产者线程。 - sleep() 的场景:
sleep()主要用于 线程延时控制。如果我们希望线程定期执行某个任务,或者模拟某些操作的延时,可以使用sleep()来实现。
生产者-消费者模型
在生产者-消费者模型中,wait() 和 notify() 经常用来实现线程间的同步。例如,生产者线程可以在缓冲区满时调用 wait(),消费者线程在缓冲区为空时也会调用 wait(),而当某个线程完成操作后,另一个线程通过 notify() 唤醒它。
public class ProducerConsumerExample {
private static final Object lock = new Object();
private static int buffer = 0;
public static void main(String[] args) {
Thread producer = new Thread(() -> {
synchronized (lock) {
while (true) {
if (buffer == 10) {
try {
lock.wait(); // 缓冲区满时,生产者等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} else {
buffer++;
System.out.println("Produced: " + buffer);
lock.notify(); // 唤醒消费者线程
}
}
}
});
Thread consumer = new Thread(() -> {
synchronized (lock) {
while (true) {
if (buffer == 0) {
try {
lock.wait(); // 缓冲区空时,消费者等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} else {
buffer--;
System.out.println("Consumed: " + buffer);
lock.notify(); // 唤醒生产者线程
}
}
}
});
producer.start();
consumer.start();
}
}
性能优化和注意事项
- 使用 sleep() 时要小心:因为
sleep()不释放锁,长时间的休眠会导致其他线程无法访问同步资源,可能会导致死锁或性能瓶颈。因此,避免在长时间持有锁的情况下调用sleep()。 - wait() 和 sleep() 的异常处理:
wait()和sleep()都会抛出InterruptedException,因此需要在调用时进行适当的异常处理。InterruptedException表示线程在等待或休眠期间被中断,因此需要确保线程在中断时做出正确的响应。 - 避免不必要的阻塞:尽量避免在不需要阻塞的情况下使用
wait()或sleep(),过度的阻塞会导致性能下降,尤其是在多线程密集型应用中。
死锁问题
如果一个线程持有锁并调用了 sleep(),而另外一个线程请求该锁并进入 wait(),那么可能会导致死锁问题。例如,线程 A 调用 sleep(),同时线程 B 进入 wait(),但由于 A 持有锁,B 永远得不到锁,从而永远处于等待状态。
public class DeadlockExample {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
try {
Thread.sleep(1000); // 模拟执行时间
synchronized (lock2) {
System.out.println("Thread1: Acquired both locks.");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
try {
Thread.sleep(1000); // 模拟执行时间
synchronized (lock1) {
System.out.println("Thread2: Acquired both locks.");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread1.start();
thread2.start();
}
}
在这个例子中,thread1 和 thread2 可能导致死锁,因为它们分别持有 lock1 和 lock2,并且等待对方释放锁,从而永远无法继续执行。
总结
wait() 用于线程通信协作,sleep()用来延时等待。开发时严禁在同步代码块里长时间调用 sleep(),不然极易引发死锁问题。合理区分二者适用场景,规范处理中断异常,规避无效阻塞,才能写出安全高效的多线程代码,保障并发程序稳定运行。
以上关于Java中wait()与sleep()方法的不同点是什么?的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » Java中wait()与sleep()方法的不同点是什么?
微信
支付宝