Кто вызывает метод прерывания Java(), если нет?

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

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

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

Ответ 1

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

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

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

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


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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

Однако вы не должны рассматривать только InterruptedException как команду "quit". Вместо этого вы должны думать о прерываниях как о способе управления текущим состоянием потоков, так же, как это делает 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();
}

Ответ 4

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

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

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

Ответ 5

Вы могли бы это узнать, создав свой собственный класс потоков (расширяя java.lang.Thread) и переопределяя метод interrupt(), в котором вы записываете stacktrace в, скажем, в поле 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();
    }
}

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Существует много способов, по которым могут быть прерывания, могут быть тайм-ауты, прерывания JVM и т.д.

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

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

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