Может ли Thread выполнять дальнейшие инструкции после вызова target.wait (), без вызова target.notify ()? [Дубликат]

Вместо flexbox я рекомендую использовать столбцы для таких сеток. Как вы можете видеть, расстояние на нижних изображениях может быть лучше, но для собственного решения для CSS я считаю, что это довольно аккуратно. Нет больше JS:

.container {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
}

ul {
  margin: 0;
  padding: 0;
}

ul li {
  list-style: none;
  font-size: 0;
}

.portfolio ul {
  -moz-column-count: 4;
  -webkit-column-count: 4;
  column-count: 4;
  -moz-column-gap: 3px;
  -webkit-column-gap: 3px;
  column-gap: 3px;
}

.portfolio ul:hover img {
  opacity: 0.3;
}

.portfolio ul:hover img:hover {
  opacity: 1;
}

.portfolio ul li {
  margin-bottom: 3px;
}

.portfolio ul li img {
  max-width: 100%;
  transition: 0.8s opacity;
}

4
задан Charles Menguy 6 January 2013 в 23:21
поделиться

6 ответов

Вы сами синхронизируете объект потока, что является неправильным использованием. Случается, что умирающий поток выполнения всегда вызывает notify на свой объект Thread: Thread.join полагается на этот . Поэтому понятно, почему вы получаете то же поведение с вашим notify и без него.

Решение: используйте отдельный объект для координации потоков; это стандартная практика.

7
ответ дан Marko Topolnik 22 August 2018 в 00:29
поделиться
  • 1
    +1 для использования отдельной нити для согласования. Если вы не знаете, что другие части системы делают с объектом, то вы не можете полагаться на него для синхронизации. – Roger Lindsjö 7 January 2013 в 00:09
  • 2
    Вы правы, но не notify, вызывается метод this.notifyAll. – Eddie Jamsession 7 January 2013 в 00:22
  • 3
    Я не понимаю этот комментарий. notify совпадает с this.notify. – Marko Topolnik 7 January 2013 в 00:27
  • 4
    notifyAll не совпадает с notify. Это разные методы. – Eddie Jamsession 7 January 2013 в 00:28
  • 5
    Это не то же самое, но в вашем случае (только один поток в наборе ожидания), - . – Marko Topolnik 7 January 2013 в 00:29

У вас есть вложенные синхронизированные {} конструкции в двух местах. Эти конструкции кажутся чем-то странным: нить не реагирует на уведомления вообще и только возобновляется, когда ThreadB (b) завершается. Удалить это:

public class JavaApplication2 {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        try {
            System.out.println(" ### Waiting for notify");
            synchronized (b) {
                b.wait();
            }
            System.out.println(" ### Notified");
        } catch (InterruptedException e) {
        }
        System.out.println("### Total is: " + b.total);
    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        total += 1;
        System.out.println(" *** Ready to notify in 5 secs");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        System.out.println(" *** Notification sent");
        synchronized (this) {
            notify();
        }
        System.out.println(" *** 5 sec post notification");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        System.out.println(" *** ThreadB exits");
    }
}

Возможно, что код выше работает корректно: при уведомлении () текущий основной поток возобновляется через 5 секунд и до того, как мы увидим сообщение, которое ThreadB завершает. С notify () закомментировал, что основной поток возобновляется через 10 секунд и после сообщения о прекращении ThreadB, потому что notify () вызывается anywhay из другого кода. Марко Тополник объясняет, почему и откуда происходит этот вызов «за сценой» notify ().

0
ответ дан h22 22 August 2018 в 00:29
поделиться
  • 1
    Вы, кажется, используете термин «ложное пробуждение», слишком свободно - это очень специфическая концепция, и она не участвует в этом вопросе (или какой-либо другой вопрос о том, как я когда-либо видел). – Marko Topolnik 7 January 2013 в 00:09
  • 2
    Основной поток возобновляется, когда поток b завершается, даже если notify () не вызывается, проверен. – h22 7 January 2013 в 00:21
  • 3
    Конечно; notify называется в любом случае, как я объясняю в своем ответе. Это не поддельное пробуждение. – Marko Topolnik 7 January 2013 в 00:26
  • 4
    Можно также смотреть так ... Я изменил это предложение в своем ответе. – h22 7 January 2013 в 09:38

Вы не можете зависеть от того, не возвращаетесь ли вы от ожидания до уведомления: «возможны прерывания и ложные пробуждения». В общем случае вы должны завернуть вызов ожидания в цикле, пока поток должен продолжать ожидание.

1
ответ дан Patricia Shanahan 22 August 2018 в 00:29
поделиться
  • 1
    Это не отвечает на вопрос. – Gray 6 January 2013 в 23:42
  • 2
    Да, побочные пробуждения - это лишь незначительная проблема, и многие реализации вообще не проявляют их. Где бы вы ни сталкивались с детерминистически воспроизводимым поведением, вы можете быть на 100% уверены, что побочные пробуждения не имеют к этому никакого отношения. – Marko Topolnik 6 January 2013 в 23:44
  • 3
    Полностью согласился @ Марко. Мне очень не нравятся упоминания ложных пробуждений. Они, безусловно, возможны, но крайне редки. Скорее всего, ошибки ошибок ошибочны. См. Этот неправильный ответ: stackoverflow.com/a/2960667/179850 – Gray 6 January 2013 в 23:50

Метод notifyAll() вызывается для объекта Thread конечной нити. Этот факт странно задокументирован в описании Thread.join со следующим предложением:

По мере того, как поток завершается, этот метод this.notifyAll вызывается. Рекомендуется, чтобы приложения не использовали wait, notify или notifyAll для экземпляров Thread.

Таким образом, если вы явно не читаете описание join, которое вы не обязательно придется, вы не узнаете причину странного поведения.

2
ответ дан Pcgomes 22 August 2018 в 00:29
поделиться

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

Хотя я не знаю нигде, что это указано, Thread уведомляет себя, когда он заканчивается. Это подразумевается в способе реализации метода join. Это код для join:

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

(Из исходного кода JDK7)

Как вы можете видеть, вызовы wait имеют смысл, если где-то там является вызовом notify, который вызывается после окончания потока. Тот же вызов notify позволяет завершить вашу программу.

1
ответ дан Simon G. 22 August 2018 в 00:29
поделиться

Я делал то же тестирование на операции wait / notify при чтении OCP SE 7, хороший catch. Я думаю, мы должны позволить автору объяснить.

0
ответ дан sotondolphin 22 August 2018 в 00:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: