Java: правильно ли это приостанавливает поток?

Мне любопытно, можно ли приостановить поток t в Java и позволить другому потоку возобновить его позже, запустив t следующий код паузы:

while(true) {
  try {
    synchronized(t) { 
      t.wait();
    }
  } catch(InterruptedException e) {
    break;
  }
}

А затем возобновить поток t, вызвав в нем .interrupt(). Однако я читал о ложных пробуждениях, и поэтому мне стало интересно, может ли мой код выйти из цикла while, несмотря на то, что никакой другой поток не вызывает в нем .interrupt(). Хотя этот ответ и этот ответ заявить, что нет ложных прерываний, и, следовательно, мой код никогда не даст сбой, документация по Java, похоже, не решает эту проблему. Мой вопрос, вероятно, сводится к тому, выбрасывается ли когда-либо InterruptedException без прерывания потока .interrupt(). Есть ли какой-либо официальный источник или документация, подтверждающая это?


person user21820    schedule 20.08.2018    source источник
comment
Независимо от того, есть ли ложные прерывания, я не думаю, что interrupt() является хорошей идеей в этом случае, вместо этого должно помочь изменчивое логическое поле.   -  person biziclop    schedule 20.08.2018
comment
Прерывание потока — не лучший способ возобновить его, мягко говоря.   -  person khachik    schedule 20.08.2018
comment
Зачем вам использовать synchronized для объекта потока? Вы синхронизируете объект, используемый несколькими потоками, а не сами потоки. Используйте wait и notify для паузы и возобновления.   -  person Susmit Agrawal    schedule 20.08.2018
comment
Кроме того, если это не для целей обучения, вы, вероятно, могли бы просто выбрать из java.util.concurrent класс, который делает именно то, что вам нужно, в вашем случае, вероятно, CountdownLatch или CyclicBarrier.   -  person biziclop    schedule 20.08.2018
comment
@SusmitAgrawal: Ну, только сам поток должен приостанавливать себя, и synchronized здесь, потому что этого требует Java ...   -  person user21820    schedule 20.08.2018
comment
@biziclop: я хотел бы точно знать, как это работает или не работает, чтобы вы могли сказать, что это для моих учебных целей.   -  person user21820    schedule 20.08.2018
comment
@user21820 Вы читали это? Это очень хорошее руководство для начинающих о том, что к чему в довольно сложной модели параллелизма Java. (В любом случае вы не должны синхронизировать потоки, вы можете создать для этого выделенный объект частной блокировки.)   -  person biziclop    schedule 20.08.2018
comment
@ user21820 Вы должны прочитать, что именно делает synchronized. Чтобы понять суть, synchronized используется, когда два или более разных потока используют один и тот же объект, чтобы предотвратить одновременный доступ к объекту из потоков.   -  person Susmit Agrawal    schedule 20.08.2018
comment
@SusmitAgrawal: я знаю это, хотя с точки зрения языка мало смысла, почему .wait() должен быть заключен в синхронизированный блок. В любом случае мой вопрос заключается в том, работает ли мой код так, как указано, а не в том, существуют ли другие способы достижения той же цели.   -  person user21820    schedule 20.08.2018
comment
я не думаю, что вы правильно интерпретируете связанные ответы.   -  person Nathan Hughes    schedule 20.08.2018
comment
@NathanHughes: Хорошо, тогда, пожалуйста, опубликуйте свой ответ с официальной документацией, спасибо!   -  person user21820    schedule 21.08.2018


Ответы (1)


Сводка

Таким образом, хотя технически это работает, существует множество причин, по которым этого делать не следует. В документации Oracle указано, что прерывание следует использовать только для отмены. Но если вы сделаете это, статус прерывания очистится, а ранее ожидавший поток получит InterruptedException.


Альтернативный

Давайте рассмотрим краткий упрощенный пример.

Object obj = new Object;
synchronized (obj) {
    while(condition) {
        obj.wait();
    }
} 
  1. thread здесь получит монитор.

  2. thread начнет ждать через wait() и отпустит монитор. Всегда используйте wait() внутри условного выражения, потому что потоки могут получать ложные пробуждения от wait(). На этом этапе вы добились принуждения потока к ожиданию.

Давайте рассмотрим, как мы возвращаем поток к работе.

synchronized(obj) {
    obj.notify();
}

notify() разбудит первое ожидающее thread на мониторе. Теперь, если вы хотите, чтобы все ожидающие потоки проснулись, используйте вместо этого notifyAll(). Это предполагаемая цель и функциональность wait()/notify(), поэтому их следует использовать в течение wait()/interrupt(). Дополнительный пример см. в этой статье. .

person Impurity    schedule 20.08.2018
comment
Спасибо за ваш ответ, но мой настоящий вопрос остается: есть ли какой-либо официальный источник или документация, подтверждающая это? Что касается «назначения и функциональности» wait() и notify(), я о них знаю. Однако, как вы сказали, notify() пробуждает первый поток, ожидающий obj, и именно поэтому вместо этого я использовал t.wait(), так что каждый поток t, который приостанавливает себя, ожидает на уникальном мониторе, и любой другой поток, который имеет ссылку на t, может возобновить t. Кроме того, меня заинтриговали два ответа, в которых говорилось, что ложных прерываний нет. - person user21820; 21.08.2018
comment
Да, и именно поэтому я сказал, что мой настоящий вопрос остается без ответа. Помните, я прошу официальную документацию, подтверждающую, что прерывание потока всегда должно происходить из-за ошибки .interrupt(). Ваш ответ теперь третий, о котором я знаю на SO, который так говорит, но Nathan Hughes в комментарии к моему вопросу, кажется, ставит под сомнение это. Вот почему я хотел бы получить официальную документацию или, по крайней мере, информацию от кого-то, кто действительно видел реализацию Java. Спасибо! - person user21820; 21.08.2018
comment
Поток отправляет прерывание, вызывая interrupt для объекта Thread, чтобы поток был прерван. docs.oracle.com/javase/tutorial/essential/concurrency/ - person Impurity; 21.08.2018
comment
То есть вы говорите, что отсутствие упоминания о ложных прерываниях означает, что это невозможно? Я видел здесь много подобных рассуждений, и они не очень убедительны для меня. - person user21820; 21.08.2018
comment
Нет, вы просто просите что-то, чтобы явно поддержать ваше утверждение, в то время как я предоставляю вам доказательства в документах, которые вы просили. - person Impurity; 21.08.2018
comment
Спасибо за это косвенное доказательство, но это не то, о чем я просил. Я был очень осторожен, чтобы использовать фразы «никогда не подведут и должен всегда» в своем посте и комментариях, потому что мне не нужны только неявные доказательства. Если ваше доказательство лучшее, что кто-либо может предоставить, то я бы его принял, но, откровенно говоря, оно меня разочаровало бы. - person user21820; 21.08.2018
comment
На самом деле это явно, в нем указано, как прерывается поток, тем самым опровергая ложные прерывания. В любом случае, удачи! - person Impurity; 21.08.2018
comment
На самом деле это не так. Цитата, например, говорит нам, как поток может отправить прерывание, потому что в конце концов документация предназначена для программистов, которые хотят знать ответ на вопрос, как я могу прервать этот поток?. Цитата не говорит нам, нет ли абсолютно никакого другого способа прерывания потока (похоже, у некоторых других языков программирования есть проблема с ложными прерываниями), и это то, что я ищу. Спасибо, в любом случае! знак равно - person user21820; 21.08.2018
comment
Я бы порекомендовал точно прочитать цель прерывания потока, чтобы лучше понять последствия того, что я и другие пытаются вам сказать, поскольку ответ здесь, я просто думаю, что есть недоразумение. - person Impurity; 21.08.2018