wait()和sleep()的区别

2023-05-19 10:39:41 浏览数 (2)

  • 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");
            }
        }
    }
}

在上述代码中,我们创建了两个线程:SleepThreadWaitThread。它们都使用了同一个对象锁 lock

  • SleepThread在同步代码块中执行,并调用 Thread.sleep(2000) 来暂停执行2秒钟。在这个过程中,SleepThread保持了对 lock 对象锁的占有。
  • WaitThread在同步代码块中执行,并调用 lock.wait(2000) 来等待2秒钟。在等待期间,WaitThread会释放对 lock 对象锁的占有,并进入等待状态。
  • SleepThreadWaitThread 中的暂停或等待时间结束后,它们都会继续执行,并释放对 lock 对象锁的占有。

关于对象锁和 sleep()wait() 的操作,我们可以观察到以下情况:

  • sleep() 不释放对象锁,即使线程暂停执行,仍然持有对象锁,其他线程无法进入该同步代码块。
  • wait() 会释放对象锁,使得其他线程有机会获取该对象锁并执行相应的同步代码块。

这里调用的必须是lock对象的wait()方法。如果在等待期间,其他线程获得了相同对象锁并执行了关联的同步代码块,那么当notify()notifyAll()方法被调用唤醒等待的线程时,等待线程会继续执行,但是可能无法立即执行等待之后的代码。

当一个线程通过调用wait()方法释放对象锁后,它进入了等待状态,并等待其他线程调用相同对象上的notify()notifyAll()方法来唤醒它。在这段等待的时间内,其他线程有机会获取对象锁,并执行与之关联的同步代码块。

当调用notify()notifyAll()方法来唤醒等待的线程时,被唤醒的线程会重新竞争对象锁。然而,并不保证等待线程会立即获得对象锁。如果其他线程在等待线程之前抢占了对象锁,等待线程仍然需要等待其他线程释放对象锁后,才能再次获得对象锁并继续执行。

因此,在等待线程被唤醒后,它需要重新竞争对象锁,如果没有成功获得对象锁,它将继续等待,直到再次获得对象锁才能继续执行等待之后的代码。

需要注意的是,为了确保线程等待和唤醒的正确性,通常在使用wait()notify()notifyAll()时,需要遵循一定的编程规范,例如在同步代码块或同步方法中使用,避免竞争条件等。这样可以保证等待和唤醒的正确性,并避免可能的死锁或其他线程同步问题。

sleep()应用场景

  1. 定时任务sleep() 方法可以用于实现定时任务。通过在任务的执行过程中调用 sleep() 方法,可以使线程在指定的时间间隔内暂停执行。这对于需要按照一定时间间隔执行某个任务的场景非常有用。
  2. 模拟延迟sleep() 方法可以用于模拟程序执行中的延迟。在某些情况下,我们希望程序在执行过程中暂停一段时间,以模拟一些实际场景,比如网络请求的延迟、系统资源的加载等。
  3. 线程间的交互sleep() 方法可以用于线程间的交互和调度。通过控制不同线程的休眠时间,我们可以实现线程之间的交替执行或特定的执行顺序。
  4. 优化资源利用sleep() 方法可以用于优化资源的利用。当某个线程执行一些耗时操作,但在某些时候并不需要一直占用资源时,可以通过适当的休眠时间来减少 CPU 的占用,让其他线程有机会获得执行。

需要注意的是,sleep() 方法是一个简单的线程暂停方法,并不涉及线程的状态管理或线程间的通信。它只是让当前线程暂停执行,不会释放对象锁。因此,使用 sleep() 方法时需要注意与其他线程的协作和同步。

此外,还需要注意 sleep() 方法的精度和可靠性可能受到操作系统和系统负载等因素的影响。因此,在编写依赖于时间的逻辑时,应谨慎使用 sleep() 方法,并考虑使用更可靠的工具和机制来满足需求,例如 ScheduledExecutorServiceTimer 等。

0 人点赞