【问题标题】:How to cancel an ExecutorService in java如何在java中取消ExecutorService
【发布时间】:2011-12-22 19:48:19
【问题描述】:

我编写了一个应用程序,它使用ExecutorService 运行一些线程并等待它们完成,如下所示:

ExecutorService exService;
exService = Executors.newCachedThreadPool();
exService.execute(T1);
exService.execute(T2);
exService.shutdown();
boolean finshed = exService.awaitTermination(5, TimeUnit.MINUTES);

有时我需要取消这些线程的执行(整个ExecutorService)。
我尝试了exService.shutdownNow(),但它抛出了java.lang.InterruptedException,并且没有取消线程。
如何取消这些线程的执行?


编辑:根据南达的要求添加 T1 类代码

public class TC implements Runnable{
    private ExtractedDataBuffer Buffer;
    private Scraper scraper;
    private String AppPath;
    private boolean Succeed=false;
    private Map<String,Object> Result=null;
    private JLabel StatElement;

    public TC(ExtractedDataBuffer Buffer,String AppPath,String XMLfile,JLabel Stat) throws FileNotFoundException {
        this.Buffer = Buffer;
        this.AppPath=AppPath;
        this.StatElement=Stat;

        ScraperConfiguration config;
        config = new ScraperConfiguration(AppPath + Main.XMLFilesPath +XMLfile);
        scraper = new Scraper(config, AppPath);
    }

    private void extract(){
        try{
            mainF.SetIconStat("working", this.StatElement);
            scraper.execute();
            if(scraper.getStatus()==Scraper.STATUS_FINISHED){
                this.Succeed=true;
                Map<String,Object> tmp=new HashMap<String,Object>();
                tmp.put("UpdateTime", ((Variable) scraper.getContext().get("UpdateTime")).toString().trim());
                Buffer.setVal(this.Result);
                mainF.SetIconStat("done", this.StatElement);
            }else{
                this.Succeed=false;
                this.Result=null;
                Buffer.setVal(null);
                mainF.SetIconStat("error", this.StatElement);
            }
        }catch(Exception ex){
            this.Succeed=false;
            this.Result=null;
            Buffer.setVal(null);
            mainF.SetIconStat("error", this.StatElement);
        }
    }

    public void run() {
        this.extract();
    }    
}

【问题讨论】:

    标签: java multithreading executorservice cancellation


    【解决方案1】:

    如果您将shutdown() 更改为shutdownNow(),那么您在编写的代码中做的事情是正确的。但是,请检查 shutdownNow() 的文档:

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

    因此,您的 T1 和 T2 可能没有以正确的方式编码,并且对中断的响应不够好。你可以复制他们的代码吗?

    --

    根据你的代码,我猜需要很长时间的代码是scraper.execute(),对吧?因此,在这些方法中,您必须不断检查以下内容:

    if (Thread.interrupted()) {
       throw new InterruptedException();
    }
    

    如果中断来了,InterruptedException 将被抛出并在你的 catch 语句中捕获,线程将停止。

    【讨论】:

    • 是的 scraper.execute 是耗时的代码。而它所消耗的99%的时间,是获取一个网页内容所花费的时间。 scraper 是一个库,我无法更改它的代码;之后只有一项工作需要时间(获取页面内容),那么检查中断如何解决问题?
    • 如果是这样...您可以尝试对每个线程调用 Thread.stop() ,但这确实很危险(正如 javadoc 解释的那样)
    【解决方案2】:

    我对@9​​87654321@ 的问题是随后对get() 的调用会抛出CancellationException。有时我仍然希望能够在Future 上调用get(),以便在执行程序服务关闭后检索部分结果。在这种情况下,可以在您提交给执行程序服务的可调用对象中实现终止逻辑。使用像

    这样的字段
    private volatile boolean terminate;
    
    public void terminate() {
        terminate = true;
    }
    

    并根据需要经常检查可调用对象中的terminate。此外,您必须在某个地方记住您的可调用对象,以便您可以对所有对象调用 terminate()

    【讨论】:

      【解决方案3】:

      使用 Executor.submit 方法,它通过创建和返回可用于取消执行和/或等待完成的 Future 扩展基本方法 Executor.execute(java.lang.Runnable):

      task = Executor.submit( T1 )
      ...
      task.cancel( true )
      

      【讨论】:

      • task.cancel( true ) 也抛出异常并且不取消线程!
      猜你喜欢
      • 2018-01-05
      • 1970-01-01
      • 2016-05-24
      • 1970-01-01
      • 2015-01-03
      • 1970-01-01
      • 2013-06-09
      • 1970-01-01
      • 2012-07-31
      相关资源
      最近更新 更多