1. sleep()
方法
1.1 sleep()
的基本定义
Thread.sleep()
是 Thread
类中的一个静态方法,用于使当前正在执行的线程进入休眠状态,也就是暂停执行一段时间。sleep()
方法有两个重载版本:
Thread.sleep(long millis)
: 让当前线程休眠指定的毫秒数。Thread.sleep(long millis, int nanos)
: 让当前线程休眠指定的毫秒数和额外的纳秒数。
在指定的时间段内,线程保持阻塞状态,不占用CPU资源。休眠结束后,线程会重新进入就绪状态(Runnable),等待操作系统调度。
1.2 sleep()
的用法示例
public class SleepExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("Thread is going to sleep...");
try {
Thread.sleep(2000); // 线程休眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread has woken up.");
});
thread.start();
}
}
在这个示例中,线程在输出“Thread is going to sleep…”后进入休眠状态,暂停执行2秒钟,之后继续执行并输出“Thread has woken up.”。
1.3 sleep()
的主要特性
- 不释放锁:当线程调用
sleep()
时,它仍然持有着任何已获得的锁,因此其他线程无法访问这些锁保护的资源。 - 不依赖同步:
sleep()
不需要与任何同步机制配合使用,任何线程都可以在任何地方调用sleep()
。 - 用于暂停线程执行:
sleep()
方法主要用于控制线程的执行节奏,比如定时任务、轮询机制等。
2. wait()
方法
2.1 wait()
的基本定义
wait()
是 Object
类中的一个实例方法,用于使当前线程等待,直到其他线程调用该对象的 notify()
或 notifyAll()
方法来唤醒它。wait()
方法通常与同步(synchronized
)块结合使用,以协调多个线程对共享资源的访问。
wait()
方法有三个重载版本:
wait()
: 让当前线程无限期地等待,直到它被通知(notify()
)。wait(long timeout)
: 让当前线程等待指定的时间,如果在这段时间内没有被通知,线程会自动唤醒。wait(long timeout, int nanos)
: 让当前线程等待指定的时间和纳秒数。
2.2 wait()
的用法示例
public class WaitExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 1 is waiting...");
try {
lock.wait(); // 线程1等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 is resumed.");
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 is notifying...");
lock.notify(); // 唤醒等待的线程1
}
});
thread1.start();
try {
Thread.sleep(1000); // 确保线程1先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
在这个示例中,thread1
在 lock
对象的监视器上等待,直到 thread2
调用 lock.notify()
来唤醒它。
2.3 wait()
的主要特性
- 释放锁:当线程调用
wait()
时,它会释放它持有的锁,从而允许其他线程进入同步块并访问共享资源。 - 依赖同步:
wait()
必须在同步块或同步方法中调用,调用wait()
的线程必须持有对象的监视器(锁)。 - 用于线程间通信:
wait()
通常用于线程间通信机制,例如生产者-消费者模型,在这种模式下,生产者和消费者线程之间需要通过wait()
和notify()
进行协调。
3. sleep()
和 wait()
的主要区别
3.1 所属类不同
sleep()
:sleep()
是Thread
类的静态方法,作用于当前正在执行的线程。wait()
:wait()
是Object
类的实例方法,作用于调用wait()
方法的对象的监视器。
3.2 锁的处理方式不同
sleep()
:sleep()
不会释放线程持有的锁。调用sleep()
时,线程仍然持有锁,因此其他线程无法访问这些锁保护的资源。wait()
:wait()
会释放当前线程持有的锁,以便其他线程可以获取这个锁,并继续执行同步块内的代码。
3.3 用途不同
sleep()
:用于简单的线程暂停,不涉及线程间的协作或通信。适合控制线程的执行节奏,如定时任务、间隔执行等。wait()
:用于线程间的通信和协作,通常与notify()
或notifyAll()
一起使用,以协调多个线程对共享资源的访问。
3.4 必须在同步块中使用的要求
sleep()
:可以在任何地方调用,不需要在同步块或同步方法中使用。wait()
:必须在同步块或同步方法中调用,且调用线程必须持有该对象的监视器(锁)。
3.5 唤醒方式不同
sleep()
:线程在指定的时间结束后自动唤醒,或者可以被interrupt()
中断唤醒。wait()
:线程必须等待另一个线程调用notify()
或notifyAll()
方法来唤醒,或者被interrupt()
中断唤醒。
4. 实际应用场景
4.1 sleep()
的应用场景
-
定时任务:在某些场景下,可能需要定期执行某些任务,例如每隔一段时间检查某些状态或执行某个动作。使用
sleep()
可以暂停线程执行,直到下一次执行时间。 -
简单的等待机制:当一个线程需要等待一段时间再继续执行时,
sleep()
是一种简单有效的方式。例如,在轮询某个资源的状态时,可以使用sleep()
插入等待时间,避免频繁检查。
4.2 wait()
的应用场景
-
生产者-消费者模型:在生产者-消费者模型中,生产者线程生成数据并将其放入缓冲区,而消费者线程从缓冲区中取出数据进行处理。如果缓冲区满了,生产者线程必须等待消费者取出数据后再继续生成。同样,如果缓冲区空了,消费者线程必须等待生产者生成数据。在这种情况下,
wait()
和notify()
被用来协调生产者和消费者之间的操作。 -
线程间的协作:在需要多个线程协调完成一个任务时,
wait()
和notify()
非常有用。例如,在一个复杂的计算任务中,多个线程可能需要依赖前一个线程的结果才能继续执行。通过使用wait()
使得线程等待,直到另一个线程完成某些操作并通知它继续执行。
5. 总结
在Java多线程编程中,sleep()
和 wait()
都是控制线程执行的重要工具,但它们在功能、用途和行为上有着显著的区别:
-
sleep()
:用于暂停当前线程的执行,不涉及线程间的同步或通信。线程在休眠期间仍持有任何已获得的锁,但不会消耗CPU资源。适合用于定时任务或简单的等待机制。 -
wait()
:用于线程间的通信和协调,通常与同步机制结合使用。wait()
使线程进入等待状态,同时释放持有的锁,直到接收到notify()
或notifyAll()
信号后被唤醒。适合用于复杂的线程协作场景,如生产者-消费者模型。