2016-03-17 74 views
1

我正在尝试编写一个程序,它将在多个Java工作线程中划分工作。问题是,当我从命令行运行它时,它永远不会返回。我没有得到我的提示,最终必须按ctrl-c关闭程序。使用ExecutorService的Java应用程序永远不会关闭

我它简化为以下琐碎的情况下

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

public class TestExeServ { 

    private class ExpensiveTask implements Callable<Integer>{ 
     private final String msg; 
     public ExpensiveTask(String str){ 
      this.msg = str; 
     } 

     @Override 
     public Integer call() { 
      System.out.println("My message was " + msg); 
      return 1; 
     } 
    } 

    private void run() 
    { 
     final ExecutorService exeServ = Executors.newFixedThreadPool(2); 
     Future<Integer> result = exeServ.submit(new ExpensiveTask("Hello!")); 
     try { 
      System.out.println(" Task is done, it returned " + result.get()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]) 
    { 
     System.out.println("Start");  

     TestExeServ tes = new TestExeServ(); 
     tes.run(); 
     System.out.println("Done"); 
    }  
} 

这个程序的输出是

[email protected]:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ 
    Start 
    my message was Hello! 
    Task is done, it returned 1 
    done 

就是这样。它挂在那里。没有提示。如果我删除ExecutorService.submit行,我得到

[email protected]:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ 
    Start 
    done 
    [email protected]:/local/mnt/workspace/TestExeServ/bin$ 

程序自然关闭。

是否有一些清理任务需要在ExecutorService上执行,我做得不好?我假设.get()调用加入了线程。情况并非如此吗?

+2

您需要关闭执行程序 –

+1

或者使用生成守护程序线程的线程工厂。 – assylias

+2

或设置标志allowCoreThreadTimeout [ThreadPoolExecutor应用程序没有完成](http://stackoverflow.com/q/30633698/217324) –

回答

5

您必须致电ExecutorService#shutdown()ExecutorService#shutdownNow()来终止执行程序的线程池。否则线程将保持活动状态,从而阻止JVM终止。

ExecutorService类的Javadoc:

一个ExecutorService可以被关闭,这将导致其拒绝新任务。为关闭ExecutorService提供了两种不同的方法。 shutdown()方法将允许之前提交的任务在终止前执行,而shutdownNow()方法阻止等待任务启动并尝试停止当前正在执行的任务。终止时,执行者没有主动执行的任务,没有任务等待执行,也不能提交新的任务。

需要注意的是,作为最后的手段,在ThreadPoolExecutor您使用会自行关闭时,它的垃圾收集 - 其finalize()方法调用shutdown()。但是,最好不要依赖这个并明确关闭执行程序。


由于@mre在注释中说,我会让它明确 - 你可以安全地只需拨打exeServ.shutdown()run()方法结束,因为Future.get()会阻塞,因此,当代码执行后get()你不要再需要执行者了。但是,如果这是更复杂的真实场景的简化版本,则可能需要找到合适的地方以安全地拨打shutdown()

+0

而'shutdownNow'可以,因为'result.get'将会阻塞,直到任务完成,否则你冒着取消它的风险。 – mre

相关问题