Кто вызывает метод Java Thread Interrupt (), если я не? - PullRequest
80 голосов
/ 24 января 2010

Я прочитал и перечитал Java Concurrency на практике, я прочитал несколько тем здесь на эту тему, я прочитал статью IBM Работа с InterruptedException , и все же есть кое-что, что я просто не понять, что, я думаю, можно разбить на два вопроса:

  1. Если я сам никогда не прерываю другие потоки, что может вызвать InterruptedException ?

  2. Если я никогда не прерываю другие потоки самостоятельно, используя interrupt () (скажем, потому что я использую другие средства для отмены своих рабочих потоков, такие как отравляющие таблетки и while ( ! отменено) цикл стиля [как объясняется в JCIP]), что тогда означает InterruptedException ? Что я должен делать, когда поймал его? Выключить мое приложение?

Ответы [ 8 ]

47 голосов
/ 24 января 2010

Механизм прерывания потока является предпочтительным способом заставить (взаимодействующий) поток ответить на запрос, чтобы остановить то, что он делает. Любой поток (включая сам поток, я думаю) может вызвать interrupt() в потоке.

На практике обычные сценарии использования для interrupt() включают в себя какую-то платформу или менеджер, говорящий некоторому рабочему потоку прекратить то, что они делают. Если рабочий поток «осведомлен о прерывании», он заметит, что он был прерван из-за исключения или путем периодической проверки его флага прерывания. Заметив, что это было прервано, хорошо ведущий себя поток откажется от того, что он делает, и завершит себя.

Принимая во внимание приведенный выше вариант использования, ваш код, скорее всего, будет прерван, если он будет запущен в среде Java или из какого-либо рабочего потока. И когда он прерван, ваш код должен отказаться от того, что он делает, и заставить себя завершиться наиболее подходящим способом. В зависимости от того, как был вызван ваш код, это может быть сделано путем возврата или выдачи какого-либо подходящего исключения. Но это, вероятно, не следует называть System.exit(). (Ваше приложение не обязательно знает, почему оно было прервано, и оно, конечно, не знает, существуют ли другие потоки, которые должны быть прерваны платформой.)

С другой стороны, если ваш код не предназначен для работы под управлением какой-либо платформы, вы можете утверждать, что InterruptedException является неожиданным исключением; то есть ошибка. В этом случае вы должны обработать исключение так же, как и другие ошибки; например оберните его в непроверенное исключение, перехватите и зарегистрируйте его в тот же момент, когда вы работаете с другими неожиданными непроверенными исключениями. (Как вариант, ваше приложение может просто игнорировать прерывание и продолжать делать то, что оно делало.)


1) Если я сам никогда не прерываю другие потоки, что может вызвать InterruptedException?

Один пример, если ваши Runnable объекты выполняются с использованием ExecutorService и shutdownNow() вызывается в службе. И теоретически любой сторонний пул потоков или инфраструктура управления потоками могут на законных основаниях делать что-то подобное.

2) Если я никогда не прерываю другие потоки самостоятельно, используя interrupt () ... что тогда означает InterruptedException? Что я должен делать, когда поймал его? Выключить мое приложение?

Вам необходимо проанализировать кодовую базу, чтобы выяснить, что делает вызовы interrupt() и почему. Как только вы поняли это, вы можете понять, что >> нужно делать вашей << части приложения. </p>

Пока вы не знаете, почему выбрасывается InterruptedException, я бы посоветовал трактовать это как серьезную ошибку; например напечатайте трассировку стека в файл журнала и закройте приложение. (Очевидно, что это не всегда правильный ответ ... но дело в том, что это «ошибка», и о ней нужно сообщить вниманию разработчика / сопровождающего.)

3) Как мне узнать, кто / что звонит interrupt()?

Нет хорошего ответа на это. Лучшее, что я могу предложить, - это установить точку останова на Thread.interrupt() и посмотреть на стек вызовов.

12 голосов
/ 24 января 2010

Если вы решите интегрировать свой код с другими библиотеками, они могут вызвать interrupt() для вашего кода. например если в будущем вы решите выполнить свой код в ExecutorService , то это может привести к отключению через interrupt().

Короче говоря, я бы подумал не только о том, где ваш код выполняется сейчас , но и в каком контексте он может выполняться в будущем. например ты собираешься положить его в библиотеку? Контейнер ? Как другие люди будут использовать это? Собираетесь ли вы использовать его повторно?

9 голосов
/ 12 октября 2012

Как уже отмечали другие, прерывание потока (фактически, прерывание блокирующего вызова) обычно используется для целей чистого завершения или отмены текущего действия.

Однако вы не должны рассматривать InterruptedException в одиночку как «команду выхода». Вместо этого вам следует рассматривать прерывания как средство управления текущим состоянием потоков, во многом так же, как Object.notify(). Точно так же, как вы проверяете текущее состояние после пробуждения от вызова на Object.wait() (вы не предполагаете, что пробуждение означает, что ваше условие ожидания выполнено), после подталкивания с прерыванием вы должны проверить почему вы были прерваны. Обычно есть способ сделать это. Например, java.util.concurrent.FutureTask имеет метод isCancelled().

Пример кода:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}
3 голосов
/ 24 января 2010

Проблема с вопросом - «Я». «Я» обычно относится к одному экземпляру класса. Я имею в виду, что любой конкретный фрагмент низкоуровневого кода (класса) не должен полагаться на реализацию всей системы. Сказав, что вы действительно приняли некоторые «архитектурные» решения (например, на какой платформе работать).

Возможные непредвиденные прерывания, поступающие из JRE, отменяются в java.util.concurrent и завершают работу апплетов.

Обработка прерываний потока обычно пишется неправильно. Поэтому я предлагаю архитектурное решение, чтобы избежать прерываний, где это возможно. Однако прерывания обработки кода всегда должны быть написаны правильно. Теперь не могу выводить прерывания с платформы.

2 голосов
/ 12 ноября 2012

Вы можете узнать это, создав собственный класс потока (расширяющий java.lang.Thread) и переопределив метод interrupt(), в котором вы записываете трассировку стека, скажем, в поле String, а затем переводите в super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}
1 голос
/ 24 января 2010

Как уже упоминалось, другая библиотека может прерывать ваши потоки. Даже если у библиотеки нет явного доступа к потокам из вашего кода, они все равно могут получить список запущенных потоков и прервать их таким образом с помощью следующего метода .

0 голосов
/ 20 марта 2017

Мне кажется, я понимаю, почему вы немного озадачены прерыванием. Пожалуйста, рассмотрите мои ответы в строке:

Если я сам никогда не прерываю другие потоки, что может вызвать InterruptedException ?

Во-первых, вы можете прерывать другие потоки; Я знаю, что в JCiP упоминается, что вы никогда не должны прерывать потоки, которыми вы не владеете; Однако это утверждение должно быть правильно понято. Это означает, что ваш код, который может выполняться в любом произвольном потоке, не должен обрабатывать прерывания, поскольку, поскольку он не является владельцем потока, он не имеет ни малейшего представления о своей политике прерывания. Таким образом, вы можете запросить прерывание в других потоках, но позволить его владельцу принять меры прерывания; внутри него заложена политика прерываний, а не код вашей задачи; по крайней мере, будьте вежливы, чтобы установить флаг прерывания!

Есть много причин, по-прежнему могут быть прерывания, могут быть тайм-ауты, прерывания JVM и т. Д.

Если я никогда не прерываю другие потоки самостоятельно, используя interrupt () (скажем, потому что я использую другие средства для отмены моих рабочих потоков, такие как отравленные таблетки и цикл стилей while (! Отмененный) [как оба объяснены в JCIP] ) что тогда означает InterruptedException? Что я должен делать, когда поймал его? Выключить мое приложение?

Вы должны быть здесь очень осторожны; если вы владеете потоком, который выдал InterruptedException (IE), то вы знаете, что делать, перехватив его, скажем, вы можете закрыть свое приложение / службу или вы можете заменить этот уничтоженный поток новым! Однако, если вы не являетесь владельцем потока, то после перехвата IE либо перебросьте его выше в стек вызовов, либо после выполнения каких-либо действий (возможно, ведение журнала) сбросьте статус прерывания, чтобы код, которому принадлежит этот поток, когда элемент управления достигнет его, мог узнайте, что поток был прерван, и, следовательно, выполняйте действия, так как только он знает политику прерывания.

Надеюсь, это помогло.

0 голосов
/ 24 января 2010

InterruptedException говорит, что подпрограмма может быть прервана, но не обязательно, что она будет.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...