Подтвердить что ты не робот

Нужно ли мне синхронизировать вызов метода прерывания?

Консультирование JavaDocs и исходного кода метода Thread.interrupt() в Java SE 7 Я нашел это:

public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0(); //1, Outside of the synchronized block
}

//...

private native void interrupt0();

Как видно, вызов native метода в //1 находится вне синхронизированного блока. Итак, безопасно ли, если вы не вызываете метод interrupt() в блок synchronized?

Thread t;
//something else
t.interrupt(); //Not in a synchronized block

Будет ли это потокобезопасным? Что делать, если более 1 поток попытается прервать его одновременно? Как будет вести себя собственный метод interrupt0?

4b9b3361

Ответ 1

Я бы сказал, да... это поточно-безопасный.

Причины:

  • Если бы приложения требовали вызвать interrupt() в блоке synchronized, тогда спецификация (javadoc) скажет так, а также скажет, какой объект вам нужно синхронизировать, чтобы получить thread- безопасность. Фактически, javadoc ничего не говорит об этом.

  • Если бы приложения требовали вызвать interrupt() в блоке synchronized, тогда учебник Oracle Java Tutorial на Concurrency упомянул бы его на этой странице. Это не так.

  • Если внешняя синхронизация на объекте Thread была необходима, чтобы сделать вызов interrupt() потокобезопасным, тогда трудно объяснить, почему метод выполняет внутреннюю синхронизацию. (Они могли/могли бы сделать весь метод синхронизированным, если это было необходимо.)

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

Ответ 2

Вопрос

@xehpuk заслуживает большего внимания:

Зачем ему нужна синхронизация? И на каком объекте?

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

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

Итак, когда мы говорим о прерывании потока, о каких состояниях мы говорим?

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

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

Ответ 3

Да, источник говорит, что прерывание мертвой нити не влияет. Так что это будет поточно-по существу.

В нем говорится: "Прерывание нити, которая не жива, не нуждается в эффекте".

Прерывает этот поток. Если текущий поток не прерывается сам, который всегда разрешен, метод checkAccess() этого вызывается thread, что может вызвать выброс SecurityException. Если этот поток заблокирован при вызове wait(), wait (long), или wait (long, int) класса Object, или join(), join (long), join (long, int), sleep (long) или sleep (long, int), методы этого класса, то его статус прерывания будет очищен, и он будет получите InterruptedException. Если этот поток заблокирован в I/O работа над java.nio.channels.InterruptibleChannel прерывистый канал, тогда канал будет закрыт, поток interruptstatus будет установлен, и поток получит java.nio.channels.ClosedByInterruptException. Если этот поток заблокирован в java.nio.channels.Selector, тогда прерывание потока статус будет установлен, и он немедленно вернется из выбора возможно, с ненулевым значением, как если бы селектор java.nio.channels. Вызывается метод пробуждения. Если ни один из предыдущие условия сохраняются, то этот статус прерывания потока будет задавать. Прерывание нити, которая не жива, не нуждается в эффекте.