Я написал поток, он занимает слишком много времени, чтобы выполнить, и кажется, что это не сделано полностью. Я хочу прекратить поток изящно. Любая помощь?
Как изящно остановить поток java?
Ответ 1
Хороший способ сделать это состоит в том, чтобы run()
Thread защищался переменной boolean
и устанавливал его в true
снаружи, когда вы хотите его остановить, например:
class MyThread extends Thread
{
volatile boolean finished = false;
public void stopMe()
{
finished = true;
}
public void run()
{
while (!finished)
{
//do dirty work
}
}
}
Когда-то существовал метод stop()
, но, как говорится в документации,
Этот метод по своей сути является небезопасным. Остановка потока с помощью Thread.stop заставляет его разблокировать все мониторы, которые он заблокировал (как естественное следствие неконтролируемого исключения ThreadDeath, распространяющегося по стеку). Если какой-либо из объектов, ранее защищенных этими мониторами, находился в противоречивом состоянии, поврежденные объекты становятся видимыми для других потоков, что может привести к произвольному поведению.
Вот почему у вас должен быть охранник.
Ответ 2
Плохая часть об использовании флага для остановки вашего потока заключается в том, что если поток ждет или спящий, вам придется подождать, пока он закончит ожидание/спящий режим. Если вы вызовете метод прерывания в потоке, это приведет к тому, что вызов ожидания или сна вызовет исключение InterruptedException.
Вызов прерывания() также устанавливает прерванное свойство, которое вы можете использовать в качестве флага, чтобы проверить, следует ли прекращать (в случае, если поток не ждет или не спящий).
Вы можете написать метод запуска потока, чтобы исключение InterruptedException находилось за пределами любой логики цикла, выполняемой потоком, или вы можете поймать исключение в цикле и близко к вызову, бросающему исключение, установив флаг прерывания внутри catch блок для InterruptedException, чтобы поток не потерял из-за того, что он был прерван. Прерванный поток все еще может контролировать и заканчивать обработку на своих условиях.
Скажем, я хочу написать рабочий поток, который работает с шагом, где по какой-то причине поспать посередине, и я не хочу покидать сон, чтобы завершить обработку, не выполняя оставшуюся работу для этого приращения, Я только хочу, чтобы он ушел, если он находится в промежутках между ними:
class MyThread extends Thread
{
public void run()
{
while (!Thread.currentThread().isInterrupted())
{
doFirstPartOfIncrement();
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
// restore interrupt flag
Thread.currentThread().interrupt();
}
doSecondPartOfIncrement();
}
}
}
Ответ 3
Вы не должны убивать Thread из другого. Он считался довольно дурной привычкой. Однако есть много способов. Вы можете использовать оператор return
из потока run
.
Или вы можете проверить, был ли поток уже прерван, а затем он отменит его работу. F.E.
while (!isInterrupted()) {
// doStuff
}
Ответ 4
Сделайте volatile boolean stop
где-нибудь. Затем в коде, который выполняется в потоке, регулярно делайте
if (stop) // end gracefully by breaking out of loop or whatever
Чтобы остановить поток, установите stop
в true
.
Я думаю, вы должны сделать это вручную таким образом. В конце концов, только код, выполняющийся в потоке, имеет представление о том, что есть и не является изящным.
Ответ 5
Вам необходимо отправить сообщение остановки в Thread, и сам поток должен принять меры, если сообщение получено. Это довольно легко, если долгое действие находится внутри цикла:
public class StoppableThread extends Thread {
private volatile boolean stop = false;
public void stopGracefully() {
stop = true;
}
public void run() {
boolean finished = false;
while (!stop && !finished) {
// long running action - finished will be true once work is done
}
}
}
Ответ 6
Для того, чтобы поток останавливался сам, никто, кажется, не упомянул (неверно), используя исключение:
abstract class SelfStoppingThread extends Thread {
@Override
public final void run() {
try {
doRun();
} catch (final Stop stop) {
//optional logging
}
}
abstract void doRun();
protected final void stopSelf() {
throw new Stop();
}
private static final class Stop extends RuntimeException {};
}
Подкласс просто должен переопределить doRun(), как обычно, с потоком, и вызвать stopSelf(), когда захочет остановиться. IMO он чувствует себя более чистым, чем использование флага в цикле while.