Как убить нить Java

Как убить нить Java

1. Вступление

В этой краткой статьеwe’ll cover stopping a Thread in Java – which is not that simple since the Thread.stop() method is deprecated.

Как объяснено вthis update from Oracle,stop() может привести к повреждению контролируемых объектов.

2. Использование флага

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

Для этого мы будем использовать атомарный флаг:

public class ControlSubThread implements Runnable {

    private Thread worker;
    private final AtomicBoolean running = new AtomicBoolean(false);
    private int interval;

    public ControlSubThread(int sleepInterval) {
        interval = sleepInterval;
    }

    public void start() {
        worker = new Thread(this);
        worker.start();
    }

    public void stop() {
        running.set(false);
    }

    public void run() {
        running.set(true);
        while (running.get()) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e){
                Thread.currentThread().interrupt();
                System.out.println(
                  "Thread was interrupted, Failed to complete operation");
            }
            // do something here
         }
    }
}

Вместо того, чтобы иметь циклwhile, оценивающий константуtrue, мы используемAtomicBoolean, и теперь мы можем начать / остановить выполнение, установив для него значениеtrue/false.

Как объясняется в нашемintroduction to Atomic Variables, использованиеAtomicBoolean предотвращает конфликты при установке и проверке переменной из разных потоков.

3. ПрерываниеThread

Что происходит, если дляsleep() задан длинный интервал, или если мы ждемlock, который может никогда не быть выпущен?

Мы рискуем заблокироваться на длительный период или никогда не завершить работу чисто.

Мы можем создатьinterrupt() для этих ситуаций, давайте добавим в класс несколько методов и новый флаг:

public class ControlSubThread implements Runnable {

    private Thread worker;
    private AtomicBoolean running = new AtomicBoolean(false);
    private int interval;

    // ...

    public void interrupt() {
        running.set(false);
        worker.interrupt();
    }

    boolean isRunning() {
        return running.get();
    }

    boolean isStopped() {
        return stopped.get();
    }

    public void run() {
        running.set(true);
        while (running.get()) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e){
                Thread.currentThread().interrupt();
                System.out.println(
                  "Thread was interrupted, Failed to complete operation");
            }
            // do something
        }
    }
}

Мы добавили методinterrupt(), который устанавливает для нашего флагаrunning значение false и вызывает методinterrupt() рабочего потока.

Если при его вызове поток находится в спящем режиме,sleep() выйдет сInterruptedException,, как и любой другой блокирующий вызов.

Это вернет поток в цикл, и он завершится, посколькуrunning ложно.

4. Заключение

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

Как всегда, доступен полный исходный кодover on GitHub.