Служба исполнителя, устанавливающая флаг для остановки потока


Я запускаю simple thread, который имеет следующий метод запуска

public run()
while(!stopFlag){
   // print something Line 1
   // print something Line 2
   // print something Line 3
   // print something Line 4
}

Если я проведу этот поток через ExecutorService viz

ExecutorService exs = Executors.newFixedThreadPool(5);
exs.execute(new MyThread));

Я останавливаю ExecutorService

exs.shutdown();

Но это не останавливает поток, так как флаг не установлен в false. В другом вопросе, относящемся к той же теме, меня попросили правильно обработать InterruptedException, которое вызывается при exs.вызывается shutdown (). Но в данном случае я не делаю никаких действий, которые могут бросить InterruptedException.

Что такое стандартный способ справиться с таким случаем ?

Дальнейший вопрос Ответ, данный Сабиром, гласит: "Если ваш runnable плохо реагирует на прерывания, ничего нельзя сделать, чтобы остановить его, кроме отключения JVM. ".Похоже, это мой случай.

Но как ввести обработку InterruptedException; если я не вызываю метод, который вызывает прерываемое исключение?

2 2

2 ответа:

Если вы хотите закрыть поток, даже если этот флаг остается верным, вы должны использовать метод - ExecutorService.shutdownNow() вместо ExecutorService.shutdown()

Цитирую из Java Docs,

shutdown()

Инициирует упорядоченное завершение работы, в котором ранее представленные задачи выполнено, но никаких новых заданий принято не будет. Призыв не имеет никакого значения. дополнительный эффект, если уже выключен.

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

shutdownNow()

Пытается остановить все активно выполняемые задачи, останавливает обработку ожидающие задачи, и возвращает список задач, которые ожидали выполнения. исполнение.

Этот метод не ожидает завершения активного выполнения задач. Использовать awaitTermination сделать это.

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

Для стандартного способа я процитирую пример JDK из интерфейса ExecutorService,

Примеры Использования

Here is a sketch of a network service in which threads in a thread pool service incoming requests. It uses the preconfigured Executors.newFixedThreadPool factory method:    class NetworkService implements Runnable {    private final ServerSocket serverSocket;    private final ExecutorService pool;

   public NetworkService(int port, int poolSize)
       throws IOException {
     serverSocket = new ServerSocket(port);
     pool = Executors.newFixedThreadPool(poolSize);    }

   public void run() { // run the service
     try {
       for (;;) {
         pool.execute(new Handler(serverSocket.accept()));
       }
     } catch (IOException ex) {
       pool.shutdown();
     }    }  }

 class Handler implements Runnable {    private final Socket socket;   Handler(Socket socket) { this.socket = socket; }    public void run() {
     // read and service request on socket    }  }} The following method shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and then calling shutdownNow, if necessary, to cancel any lingering tasks:    void shutdownAndAwaitTermination(ExecutorService pool) {    pool.shutdown(); // Disable new tasks from being submitted    try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }    } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();    }  }}
Обратите внимание, что нет никаких гарантий даже с shutdownNow() .

EDIT: Если я изменю ваш while(!stopFlag) на while(!Thread.currentThread().isInterrupted()), то поток с условным циклом получает завершение работы с shutdownNow(), но не с shutdown() , поэтому поток прерывается с shutdownNow(). Я нахожусь на JDK8 и Windows 8.1. Я должен поставить спящий режим в главном потоке, чтобы служба могла получить время для настройки службы и запуска runnable. Поток запускается, входит в while, а затем останавливается, когда вызывается shutdownNow(). Я не получаю такого поведения с shutdown(), т. е. поток никогда не выходит из цикла while. Поэтому подход, чтобы сделать ваши runnables ответственными за прерывания, должен быть там, либо проверяя флаги, либо обрабатывая исключения. Если ваш runnable плохо реагирует на прерывания, ничего можно сделать, чтобы остановить его, кроме отключения СПМ.

Здесь показан один хороший подход

Ну из вашего вопроса я предполагаю, что вы пытаетесь завершить процесс изящно. Для этого вам нужно зарегистрировать shutdownHook, чтобы достичь этого. Вот пример кода для достижения этой цели.

package com.example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadManager {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Runtime.getRuntime().addShutdownHook(new Thread(){
            MyThread myThread = null;
            @Override
            public void run(){
                System.out.println("Shutting down....");
                this.myThread.stopProcess();
            }
            public Thread setMyThread(MyThread myThread){
                this.myThread=myThread;
                return this;
            }
        }.setMyThread(myThread));
        ExecutorService exs = Executors.newFixedThreadPool(5);
        myThread.setName("User");
        exs.execute(myThread);
        exs.shutdownNow();
    }
}

И в MyThread.java будет выглядеть следующим образом: -

package com.example;

public class MyThread extends Thread{
    private boolean stopFlag;

    @Override
    public void run(){
        while(!stopFlag){
           System.out.println(this.getName());
        }
    }
    public void stopProcess(){
        this.stopFlag=true;
    }
}

Теперь, если вы создадите jar-файл из этого кода и запустите его на сервере Linux, чтобы посмотреть, как он работает, выполните следующие дополнительные действия

Step 1> nohup java -jar MyThread.jar &

Нажмите ctrl+c, чтобы существовать Теперь найдите pid с помощью следующая команда

Step 2> ps -ef| grep MyThread.jar

Как только вы получили pid, выполните следующую команду, чтобы изящно остановиться

Step 3>kill -TERM <Your PID>

Когда вы проверяете nohub.out file, вывод будет выглядеть примерно следующим образом

User
User
.
.
.
User
Shutting down....
User
.
.

Помните, что если вы попытаетесь завершить работу с помощью kill -9, то вы никогда не увидите сообщение Shutting down.....

@Sabir уже обсуждают разницу между shutdown и shutdownNow. Однако я никогда не буду рекомендовать вам использовать вызов interrupt во время выполнения потоков. Может быть причина утечки памяти в реальном времени.

Упадте 1:-

public static void main(String[] args) {
    MyThread myThreads[] = new MyThread[5];
    ExecutorService exs = Executors.newFixedThreadPool(5);
    for(int i=0;i<5;++i){
        MyThread myThread = new MyThread();
        myThread.setName("User "+i);
        exs.execute(myThread);
        myThreads[i] = myThread;
    }
    Runtime.getRuntime().addShutdownHook(new Thread(){
        MyThread myThreads[] = null;
        @Override
        public void run(){
            System.out.println("Shutting down....");
            for(MyThread myThread:myThreads){
                myThread.stopProcess();
            }
        }
        public Thread setMyThread(MyThread[] myThreads){
            this.myThreads=myThreads;
            return this;
        }
    }.setMyThread(myThreads));
    exs.shutdownNow();
}