Остановить, прервать, приостановить и возобновить поток Java
Я начал читать о том, как безопасно останавливать, прерывать, приостанавливать и возобновлять Java-поток, я нашел в документации оракула следующие решения:
1- Как безопасно остановить поток:
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
- Чтобы остановить поток, я могу использовать boolean
переменная вместо volatile Thread
, но почему Oracle настаивает на том, чтобы влиять на ноль в запущенном потоке? есть ли секрет (например, освобождение ресурсов, выделенных с помощью финализатора), делающих это так?
2- Как прервать поток, который ждет долгое время:
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
Почему я должен создать новую переменную moribund
и не используя напрямую waiter.interrupt()
?
3- Как приостановить и возобновить поток:
private volatile boolean threadSuspended;
public void run() {
while (true) {
try {
Thread.sleep(interval);
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
} catch (InterruptedException e){
}
repaint();
}
}
public synchronized void mousePressed(MouseEvent e) {
e.consume();
threadSuspended = !threadSuspended;
if (!threadSuspended)
notify();
}
- почему внутри run
метод они добавили цикл while (threadSuspended)
потому что я не понимаю, какова цель его добавления, и мой код может быть скомпилирован и работать без него (с такими же результатами).
Ссылка на источник http://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
1 ответ
1. Использование местного Thread
переменная предотвращает вызов других потоков run()
метод на вашем объекте. Только поток, представленный этим экземпляром объекта, может использовать run()
метод. Как правило, это плохая практика run()
метод Thread
вручную из другого Thread
, но, конечно, возможно.
2. Этот момент необходимо объяснить в контексте пункта 1. В этой части также рассматривается случай, когда interval
очень долго, и поток должен быть остановлен как можно скорее.
Вам, безусловно, нужно аннулировать ссылку, потому что в противном случае код в части 1 просто продолжит цикл. Но подумайте, что может произойти, если вы упростите stop
метод для:
public void stop() {
waiter.interrupt();
waiter = null;
}
Так как это выполняется из другого потока, оно может быть переплетено с run()
метод любым способом. Например, threadA вызывает stop()
остановить поток B, который находится в run()
:
- поток B: сон (интервал)
- threadA: waiter.interrupt ()
- поток B: пойман InterruptedException
- threadB: вызов, чтобы перекрасить
- threadB: введите следующий цикл
- поток B: введите сон (интервал)
- нить: официант == ноль
В этом случае вместо немедленной остановки поток B выполняет еще один цикл ожидания, который не выполняет поставленную задачу: stop a thread that waits for long periods
, В данной реализации вы сначала обнуляете, а затем прерываете, что предотвращает подобное поведение.
3. Вкратце: потому что другой поток мог уведомить ваш код, не устанавливая правильный флаг. Генеральный договор notify()
в том, что звонить безвредно (но бесполезный звонок, очевидно, потребляет некоторые ресурсы). Предполагается, что все темы могут справиться с ложными пробуждениями.