English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Механизм прерывания тредов предоставляет метод для пробуждения треда из блокируемого состояния ожидания, попытки прервать текущий процесс обработки целевого треда, чтобы он ответил на новую команду. Java предоставляет разработчикам эту свободу, и мы должны ею воспользоваться.
Сегодня мы поговорим о механизме прерывания тредов в Java.
Механизм прерывания тредов предоставляет метод, который имеет два обычных использования:
Пробудите тред из блокируемого состояния ожидания и выполните соответствующие действия «под контролем прерывания».
Попробуйте сообщить целевому треду: прервите текущий процесс обработки и ответьте на новую команду.
Например, рассмотрим следующий код для первого использования:
synchronized (lock) { try { while (!check()) { lock.wait(1000); } } e.printStackTrace(); } }
Этот код использует механизм wait/notify, предоставленный Java, и тред блокируется при lock.wait(), и есть три случая, при которых тред продолжает работу.
1. Время ожидания 1000ms истекло, выполняется следующая строка кода.
2. Другой тред выполняет следующий код для активного пробуждения
synchronized (lock) { lock.notifyAll(); // или lock.notify(); }
Это также будет выполняться нормально, если выполнится следующая строка кода.
3. Другой тред требует прервать блокируемый тред
// Получить ссылку на блокируемый тред Thread a; a.interrupt();
Тред, который был «прерван», выбросит исключение InterruptedException в lock.wait().
В заключение, можно считать, что object.wait() выполняет следующие действия:
boolean checkTimeout = timeout > 0; Thread current = Thread.currentThread(); lock.addWaiter(current); while (!current.isNotified()) { if (current.isInterrupted()) { current.clearInterrupted(); throw new InterruptedException(); } if (checkTimeout) { if (timeout == 0) break; timeout--; } }
Это не совсем точно, потому что wait не использует этот способ «беглых проверок» для проверки, но логика оценки флага правильна.
Давайте начнем с операции «ручного прерывания», о которой говорилось выше
// sun.nio.ch.Interruptible public interface Interruptible { void interrupt(Thread var1); } // java.lang.Thread private volatile Interruptible blocker; private final Object blockerLock = new Object(); public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); b.interrupt(this); return; } } interrupt0(); } // Просто установить флаг прерывания private native void interrupt0();
可以看出,thread.interrupt() сначала проверяет права доступа, а затем реально вызывает interrupt0() для установки флага прерывания потока, а если текущий поток имеет Interruptible nio, то также вызывается его обратный вызов.
Обратите внимание, что interrupt0() просто устанавливает флаг прерывания потока.
Когда поток не блокируется и не находится в области object.wait(), thread.join(), Thread.sleep() и других областях, которые не контролируются логикой Java-программы, что会发生? Ответ: ничего не происходит, чтобы узнать, был ли поток прерван, необходимо активно проверять флаг прерывания.
Как проверить? Thread предоставляет два интерфейса, Thread.interrupted() и thread.isInterrupted().
// java.lang.Thread public static boolean interrupted() { return currentThread().isInterrupted(true); } public boolean isInterrupted() { return isInterrupted(false); } private native boolean isInterrupted(boolean clearInterrupted);
可以看出,оба они зависят от внутреннего isInterrupted(boolean), который возвращает, был ли поток прерван, и по необходимости очищает флаг прерывания.
Когда вызов функции может вызвать блокировку, библиотечные функции Java в строке подписи блокировки помечают throws InterruptedException и требуют编写 try catch для обработки прерывания.
Когда поток блокируется, как описано выше, Java проверяет флаг прерывания, сначала очищает его, а затем выбрасывает InterruptedException.
// java.lang.Object public final void wait() throws InterruptedException { wait(0); } public final native void wait(long timeout) throws InterruptedException;
Если поток получает InterruptedException, но затем продолжает выполнять код, вызывающий блокировку, он продолжит блокироваться, как будто ничего не произошло. Потому что Java внутренне очищает флаг прерывания!
Мы часто пишем следующие три типа кода для обработки InterruptedException:
ИнтерруptionsException передается на уровень выше для обработки.
public void foo() throws InterruptedException { synchronized (lock) { lock.wait(); } }
遇到InterruptedException时重置中断标志位。
try { synchronized (lock) { lock.wait(); } } Thread.currentThread().interrupt(); //break; }
先完成,然后重新抛出InterruptedException。
public void bar() throws InterruptedException { InterruptedException ie = null; boolean done = false; while (!done) { synchronized (lock) { try { lock.wait(); } ie = e; continue; } } done = true; } if (ie != null) { throw ie; } }
如果一个线程无视中断标志和InterruptedException,它仍然可以很好地运行。但这与我们的多线程设计初衷相违背,我们希望线程之间能够和谐有序地协作以实现特定功能。因此,受控线程应当对中断作出响应。Java留给开发者这一自由,我们应该善加利用。
以上就是本次为大家介绍的Java线程中断机制相关知识的全部内容。如果还有任何不明白的地方,可以在下方的留言区域进行讨论,感谢对呐喊教程的支持。
声明:本文内容来源于网络,版权属于原作者。内容由互联网用户自发贡献并自行上传,本网站不拥有所有权,未进行人工编辑处理,也不承担相关法律责任。如果您发现涉嫌版权的内容,请发送邮件至:notice#oldtoolbag.com(发送邮件时,请将#替换为@)进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。