Комикс: Как доказать, что сон не снимает блокировку, а ожидание снимает блокировку?

Java
Комикс: Как доказать, что сон не снимает блокировку, а ожидание снимает блокировку?

пример блокировки ожидания

public class WaitDemo {
    private static Object locker = new Object();

    public static void main(String[] args) throws InterruptedException {
        WaitDemo waitDemo = new WaitDemo();

        // 启动新线程,防止主线程被休眠
        new Thread(() -> {
            try {
                waitDemo.doWait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Thread.sleep(200); // 此行本身没有意义,是为了确保 wait() 先执行再执行 notify()
        waitDemo.doNotify();
    }

    /**
     * 执行 wait()
     */
    private void doWait() throws InterruptedException {
        synchronized (locker) {
            System.out.println("wait start.");
            locker.wait();
            System.out.println("wait end.");
        }
    }

    /**
     * 执行 notify()
     */
    private void doNotify() {
        synchronized (locker) {
            System.out.println("notify start.");
            locker.notify();
            System.out.println("notify end.");
        }
    }
}

Результат выполнения вышеуказанной программы:

wait start.

notify start.

notify end.

wait end.

Разбор кода

Как видно из кода выше, мы даемwait() иnotify()Два метода имеют одинаковую блокировку (locker), но после вызоваwait()после методаlockerЗамок выделяется, поэтому программа может выполняться нормальноnotify()Код , так как это один и тот же замок, если блокировку не снять, то она не будет выполненаnotify()кода, это также может быть подтверждено распечатанными результатами (порядок вывода результатов), поэтомуВ связи с вышеуказанной ситуациейwait()Метод заключается в том, чтобы снять блокировку.

пример блокировки сна

public class WaitDemo {
    private static Object locker = new Object();

    public static void main(String[] args) throws InterruptedException {
        WaitDemo waitDemo = new WaitDemo();
        // 启动新线程,防止主线程被休眠
        new Thread(() -> {
            synchronized (locker) {
                try {
                    System.out.println("sleep start.");
                    Thread.sleep(1000);
                    System.out.println("sleep end.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Thread.sleep(200);
        waitDemo.doNotify();
    }

    /**
     * 执行 notify()
     */
    private void doNotify() {
        synchronized (locker) {
            System.out.println("notify start.");
            locker.notify();
            System.out.println("notify end.");
        }
    }
}

Результат выполнения вышеуказанной программы:

sleep start.

sleep end.

notify start.

notify end.

Разбор кода

Как видно из кода вышеsleep(1000)После выполнения метода (номер строки: 11) вызовитеnotify()Метод не получает блокировку шкафчика, как видно из приведенных выше результатов выполнения, а после выполненияsleep(1000)метод выполняется послеnotify()метод,Так что вы можете доказать звонокsleep()метод не снимает блокировку.

расширение знаний

1. В чем разница между сном и ожиданием?

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

заsleepиwaitРазница, обычный ответ таков:

  • ожидание должно использоваться с синхронизацией, а сон — нет;
  • Поток, входящий в состояние ожидания, может быть разбужен потоками notify и notifyAll, в то время как поток в спящем состоянии не может быть разбужен методом notify;
  • ожидание обычно выполняется условно, поток будет оставаться в состоянии ожидания до тех пор, пока определенное условие не станет истинным, но сон только усыпляет ваш поток;
  • Метод ожидания снимает блокировку объекта, а метод сна — нет.

Но выше ответа явно не хватает важного различия, вызывающегоwaitметод, нить становитсяWATINGсостояние при вызовеsleepметод, нить становитсяTIMED_WAITING государство.

2. Можно ли использовать ожидание в статических методах? Зачем?

нет потому чтоwaitМетод является методом экземпляра (неstaticметод), поэтому не может быть использован вstaticИсходный код выглядит следующим образом:

public final void wait() throws InterruptedException {
    wait(0);
}

3. Можно ли использовать ожидание/уведомление без синхронизации? Зачем?

Нет, потому что не совпадаетsynchronizedПри использовании программа сообщит об ошибке, как показано на следующем рисунке:

Более глубокая причина заключается в том, что не добавляяsynchronizedСлова вызовут потерю пробуждения, потерю пробуждения, поиск деталей:nuggets.capable/post/684490…

Суммировать

В этой статье мы проходимsynchronizedЗаблокируйте тот же объект, чтобы проверитьwait иsleepметодом, а затем доказать последовательностью результатов выполнения:waitметод снимает блокировку, аsleepметод не. Мы также рассказали о некоторыхwaitиsleepобщие вопросы интервью, я надеюсь, что эта статья может помочь вам.

Обратите внимание на общественный номер»Сообщество китайского языка Java” для большего количества отличного контента.