1. Обзор

В этой короткой статье мы познакомимся со стандартными методами sleep() и wait() в Java и поймем различия и сходства между ними.

2. Общие различия между wait() и sleep()

Проще говоря, wait() - это метод экземпляра, который используется для синхронизации потоков.

Он может быть вызван для любого объекта, так как метод определен прямо в java.lang.Object, но он может быть вызван только из синхронизированного блока. Он снимает блокировку объекта, так что другой поток может подключиться и получить блокировку.

С другой стороны, Thread.sleep() - это статический метод, который можно вызывать из любого контекста. Thread.sleep() приостанавливает текущий поток и не снимает блокировки.

Вот очень упрощенный начальный взгляд на эти два основных API в действии:

private static Object LOCK = new Object();

private static void sleepWaitExamples() 
  throws InterruptedException {
 
    Thread.sleep(1000);
    System.out.println(
      "Thread '" + Thread.currentThread().getName() +
      "' is woken after sleeping for 1 second");
 
    synchronized (LOCK) {
        LOCK.wait(1000);
        System.out.println("Object '" + LOCK + "' is woken after" +
          " waiting for 1 second");
    }
}

Запуск этого примера приведет к следующему выводу:

Thread ‘main’ is woken after sleeping for 1 second Object ‘[email protected]’ is woken after waiting for 1 second

3. Просыпаться wait() и sleep()

Когда мы используем метод sleep, поток запускается через указанный промежуток времени, если он не прерывается.

Для wait() процесс пробуждения немного сложнее. Мы можем разбудить поток, вызвав методы notify или notifyAll на ожидаемом мониторе.

Используйте notifyAll вместо notify, когда вы хотите разбудить все потоки, которые находятся в состоянии ожидания. Подобно самому методу wait, notify и notifyAll должны вызываться из синхронизированного контекста.

Например, вот как вы можете wait:

synchronized (b) {
    while (b.sum == 0) {
        System.out.println("Waiting for ThreadB to complete...");
        b.wait();
    }

    System.out.println("ThreadB has completed. " + 
      "Sum from that thread is: " + b.sum);
}

И затем, вот как другой поток может затем разбудить ожидающий поток, вызвав notify на мониторе:

int sum;
 
@Override 
public void run() {
    synchronized (this) {
        int i = 0;
        while (i < 100000) {
            sum += i;
            i++; 
        }
        notify(); 
    } 
}

Запуск этого примера приведет к следующему выводу

Waiting for ThreadB to complete… ThreadB has completed. Sum from that thread is: 704982704

4. Заключение

Это быстрый учебник семантики wait и sleep в Java.

В общем, мы должны использовать sleep() для контроля времени выполнения одного потока и wait() многопоточной синхронизации. Естественно, есть намного больше, чтобы исследовать после понимания основ хорошо.