Executor Service设置标志以停止线程

时间:2017-05-16 05:57:34

标签: java multithreading threadpool executorservice

我正在运行简单的customer_id | Product #1 | Product #2 ------------+------------+----------- 1 | DVD | Blu-ray 2 | DVD | ,其运行方法如下

thread

如果我通过public run() while(!stopFlag){ // print something Line 1 // print something Line 2 // print something Line 3 // print something Line 4 } viz

运行此帖子
ExecutorService

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

ExecutorService

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

处理此类案件的标准方法是什么?

进一步的问题 Sabir给出的答案说:“如果你的可运行对中断反应不好,除了关闭JVM之外什么都不能阻止它。”。这似乎是我的情况。

但是如何引入InterruptedException的处理;如果我没有调用任何抛出中断异常的方法?

2 个答案:

答案 0 :(得分:1)

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

从Java Docs引用,

shutdown()

  

启动以前提交的任务的有序关闭   已执行,但不会接受任何新任务。调用没有   如果已经关闭则会产生额外的影

     

此方法不会等待先前提交的任务完成   执行。使用awaitTermination来做到这一点。

shutdownNow()

  

尝试停止所有正在执行的任务,停止处理   等待任务,并返回正在等待的任务列表   执行。

     

此方法不等待主动执行任务终止。   使用awaitTermination来做到这一点。

     

除了努力尝试停止处理之外,没有任何保证   积极执行任务。例如,典型的实现方式   通过Thread.interrupt取消,因此任何无法响应的任务   中断可能永远不会终止。

对于标准方式,我将引用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和Windows 8.1上。我必须在主线程中进行睡眠,以便服务可以花时间设置服务并启动runnable。线程被启动,进入,然后在调用shutdownNow()时停止。我没有得到shutdown()的那种行为,即线程永远不会出现在while循环中。因此,应该通过检查标志或处理异常来使你的runnables负责中断的方法。如果您的runnable对中断没有很好的响应,那么除了关闭JVM之外,不能做任何事情来阻止它。

显示了一个好的方法here

答案 1 :(得分:0)

从您的问题中我很好地假设您正在尝试优雅地关闭该过程。为此,您需要注册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调用。它可能会导致实时环境中的内存泄漏。

Upadte 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();
}