sleep()
是Thread类的方法,用于让线程暂停一段时间,不释放对象锁。wait()
是Object类的方法,在同步代码块中使用,让线程等待并释放对象锁,直到被唤醒或超时。sleep()
是线程的静态方法,wait()
是对象的方法。sleep()
通常用于控制执行时间间隔或模拟延迟,而wait()
通常用于线程间的同步和协调。
需要注意的是,在使用wait()
和notify()
时,必须在同步代码块或同步方法中调用,以确保正确的对象锁的释放和获取。
划重点:sleep()不会释放对象锁,而wait()会释放对象锁。
示例:
代码语言:javascript复制public class ObjectLockExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new SleepThread());
Thread thread2 = new Thread(new WaitThread());
thread1.start();
thread2.start();
}
static class SleepThread implements Runnable {
public void run() {
synchronized (lock) {
System.out.println("SleepThread acquired lock");
try {
Thread.sleep(2000); // 线程暂停2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("SleepThread released lock");
}
}
}
static class WaitThread implements Runnable {
public void run() {
synchronized (lock) {
System.out.println("WaitThread acquired lock");
try {
lock.wait(2000); // 线程等待2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WaitThread released lock");
}
}
}
}
在上述代码中,我们创建了两个线程:SleepThread
和WaitThread
。它们都使用了同一个对象锁 lock
。
SleepThread
在同步代码块中执行,并调用Thread.sleep(2000)
来暂停执行2秒钟。在这个过程中,SleepThread
保持了对lock
对象锁的占有。WaitThread
在同步代码块中执行,并调用lock.wait(2000)
来等待2秒钟。在等待期间,WaitThread
会释放对lock
对象锁的占有,并进入等待状态。- 在
SleepThread
或WaitThread
中的暂停或等待时间结束后,它们都会继续执行,并释放对lock
对象锁的占有。
关于对象锁和 sleep()
、wait()
的操作,我们可以观察到以下情况:
sleep()
不释放对象锁,即使线程暂停执行,仍然持有对象锁,其他线程无法进入该同步代码块。wait()
会释放对象锁,使得其他线程有机会获取该对象锁并执行相应的同步代码块。
这里调用的必须是lock对象的wait()方法。如果在等待期间,其他线程获得了相同对象锁并执行了关联的同步代码块,那么当notify()
或notifyAll()
方法被调用唤醒等待的线程时,等待线程会继续执行,但是可能无法立即执行等待之后的代码。
当一个线程通过调用wait()
方法释放对象锁后,它进入了等待状态,并等待其他线程调用相同对象上的notify()
或notifyAll()
方法来唤醒它。在这段等待的时间内,其他线程有机会获取对象锁,并执行与之关联的同步代码块。
当调用notify()
或notifyAll()
方法来唤醒等待的线程时,被唤醒的线程会重新竞争对象锁。然而,并不保证等待线程会立即获得对象锁。如果其他线程在等待线程之前抢占了对象锁,等待线程仍然需要等待其他线程释放对象锁后,才能再次获得对象锁并继续执行。
因此,在等待线程被唤醒后,它需要重新竞争对象锁,如果没有成功获得对象锁,它将继续等待,直到再次获得对象锁才能继续执行等待之后的代码。
需要注意的是,为了确保线程等待和唤醒的正确性,通常在使用wait()
、notify()
或notifyAll()
时,需要遵循一定的编程规范,例如在同步代码块或同步方法中使用,避免竞争条件等。这样可以保证等待和唤醒的正确性,并避免可能的死锁或其他线程同步问题。
sleep()应用场景
- 定时任务:
sleep()
方法可以用于实现定时任务。通过在任务的执行过程中调用sleep()
方法,可以使线程在指定的时间间隔内暂停执行。这对于需要按照一定时间间隔执行某个任务的场景非常有用。 - 模拟延迟:
sleep()
方法可以用于模拟程序执行中的延迟。在某些情况下,我们希望程序在执行过程中暂停一段时间,以模拟一些实际场景,比如网络请求的延迟、系统资源的加载等。 - 线程间的交互:
sleep()
方法可以用于线程间的交互和调度。通过控制不同线程的休眠时间,我们可以实现线程之间的交替执行或特定的执行顺序。 - 优化资源利用:
sleep()
方法可以用于优化资源的利用。当某个线程执行一些耗时操作,但在某些时候并不需要一直占用资源时,可以通过适当的休眠时间来减少 CPU 的占用,让其他线程有机会获得执行。
需要注意的是,sleep()
方法是一个简单的线程暂停方法,并不涉及线程的状态管理或线程间的通信。它只是让当前线程暂停执行,不会释放对象锁。因此,使用 sleep()
方法时需要注意与其他线程的协作和同步。
此外,还需要注意 sleep()
方法的精度和可靠性可能受到操作系统和系统负载等因素的影响。因此,在编写依赖于时间的逻辑时,应谨慎使用 sleep()
方法,并考虑使用更可靠的工具和机制来满足需求,例如 ScheduledExecutorService
、Timer
等。