Executor Service 设置标志以停止线程

Executor Service setting the flag to stop the thread

我运行宁简单thread有运行方法如下

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

如果我 运行 这个线程通过 ExecutorService

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

我停止 ExecutorService

exs.shutdown();

但这不会停止线程,因为标志未设置为 false。在 another question related to same topic 中,我被要求正确处理调用 exs.shutdown() 时引起的 InterruptedException。 但在这种情况下,我没有执行任何可能引发 InterruptedException 的操作。

处理这种情况的标准方法是什么?

进一步提问 Sabir 给出的答案是 "If your runnable doesn't respond well to interrupts, nothing can be done to stop it other than shutting down the JVM. "。这似乎是我的情况。

但是如何介绍InterruptedException的处理;如果我不调用任何抛出中断异常的方法?

如果您愿意关闭您的线程,即使该标志仍然为真,您应该使用 - ExecutorService.shutdownNow() 方法而不是 ExecutorService.shutdown()

引用自 Java 文档,

shutdown()

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.

This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.

shutdownNow()

Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.

This method does not wait for actively executing tasks to terminate. Use awaitTermination to do that.

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt, so any task that fails to respond to interrupts may never terminate.

对于标准方式,我将引用 ExecutorService 界面中的 JDK 示例,

使用示例

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() 也无法保证。

编辑: 如果我将您的 while(!stopFlag) 更改为 while(!Thread.currentThread().isInterrupted()),则带有条件循环的线程会通过 shutdownNow() 而不是 shutdown() 所以线程被 shutdownNow() 中断。我在 JDK8 和 Windows8.1。我确实必须在主线程中休眠,以便服务有时间设置服务并启动可运行的。线程启动,进入 while 然后在调用 shutdownNow() 时停止。我没有用 shutdown() 得到这种行为,即线程永远不会退出 while 循环。因此,通过检查标志或处理异常,让您的可运行对象负责中断的方法应该存在。如果您的 runnable 不能很好地响应中断,除了关闭 JVM 之外,没有什么可以阻止它。

显示了一个好的方法here

从你的问题来看,我假设你正在尝试正常关闭进程。为此,您需要注册一个 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 文件时,输出将如下所示

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

请记住,如果您尝试使用 kill -9 关闭,您将永远不会看到 Shutting down.... 消息。

@Sabir 已经讨论了 shutdownshutdownNow 之间的区别。但是,我绝不会建议您在线程处于 运行 时使用 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();
}