1

我正在尝试编写一个程序,将工作分配给几个 java 工作线程。问题是当我从命令行运行它时它永远不会返回。我没有得到我的提示,最终必须 ctrl-c 关闭程序。

我已将其简化为以下简单的案例

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");
    }       
}

这个程序的输出是

   djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ
   Start
   my message was Hello!
    Task is done, it returned 1
   done

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

   djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ
   Start
   done
   djc@djc-linux:/local/mnt/workspace/TestExeServ/bin$

程序自然关闭。

我需要在 ExecutorService 上执行一些我没有正确执行的清理任务吗?我假设 .get() 调用加入了线程。不是这样吗?

4

1 回答 1

5

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

来自ExecutorServiceJavadoc 类:

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

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


正如@mre 在评论中所说,我会明确说明 - 你可以安全地exeServ.shutdown()在你的方法结束时调用,run()因为Future.get()会阻塞,所以当代码执行之后get()你不再需要执行程序。但是,如果这是一个更复杂的现实生活场景的简化版本,您可能需要找到正确的位置来安全地调用shutdown().

于 2016-03-17T21:19:47.903 回答