当executorService.shutdown();应该叫



我们有一个服务方法getdatapar列(),目前可能被许多客户端调用,我们使用ExecutorService调用MyCallable。然而,我发现除非我调用executorService.shutdown();应用程序永远不会退出,那么为什么应用程序不能退出,必须在应用程序退出之前手动关闭所有线程池线程呢?在服务环境中,我认为我们不需要调用executorService.shutdown();来保持应用程序的运行,对吧?

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiThreading {
    static ExecutorService executorService = Executors.newFixedThreadPool(100);
    private List<String> _BusinessUnits= new ArrayList<String>();
    public static void main(String[] args) throws Exception {
        MultiThreading  kl =new MultiThreading();
        kl.GetDataParallel();
        Thread.sleep(10000);
        System.out.println("111111111");
         //executorService.shutdown();
    }
    public   void GetDataParallel( ) throws Exception
    {
        _BusinessUnits.add("BU1");
        _BusinessUnits.add("BU2");
        _BusinessUnits.add("BU3");
        for(final String v : _BusinessUnits)
        {
            ExecutorServiceTest.executorService.submit( new MyCallable());
        }
    }
}
  class MyCallable implements Callable  {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        //return the thread name executing this callable task
        System.out.println(Thread.currentThread().getName());
        return Thread.currentThread().getName();
    }
}

通常在应用程序退出时关闭ExecutorService -大多数应用程序都有某种生命周期和关闭顺序。如果您希望应用程序在主线程完成它必须做的事情时退出,那么您希望在它的工作完成时关闭它(这意味着有一个定义良好的工作完成点,并且您可以告诉它何时完成)。

服务器端框架通常具有生命周期方法,您可以钩入这些方法来检测代码何时关闭并干净地退出。或者你可以使用虚拟机关机钩子(也许是延迟关机,直到所有当前排队的作业完成),这样无论什么代码导致程序退出,你的清理代码将运行。

一般来说,如果框架没有提供出口点,那么创建一个定义良好的出口点是一个好主意——它可以让你有一个应用程序可以被干净地卸载(也许,用更新的配置重新加载),而不需要关闭VM——我已经使用了这个技巧,能够让服务器应用程序重新配置自己,并在响应Unix信号时零停机重新加载。

所以,你的问题的简单答案是"当它不再被使用时"。在几乎任何应用程序中,都有一个点是明确无误的。

顺便说一句,为了与其他响应器之一相矛盾,ExecutorService 可以使用守护线程——您可以提供一个ThreadFactory,在启动线程之前按照您的意愿配置线程。但是我鼓励您不要使用守护线程,并在一个定义良好的点显式地关闭线程池——这不是典型的做法,但这既意味着您的代码有可能被干净地关闭,也将鼓励您考虑生命周期,这可能会导致更好的代码。

Java中有两种类型的线程(当然取决于您如何看待它们)。"用户"线程和"守护进程"线程。您的应用程序在下列情况之一结束:

  1. 呼叫System.exit()
  2. 您的应用程序中没有User线程。

注意你的main函数是由JVM在一个'User'线程上执行的,这意味着只要你还没有完成你的main函数。大多数多线程应用程序只会运行main函数来启动所需的所有线程。

Daemon线程背后的思想是,你可以做一些事情(定期),但如果所有其他任务都完成了,它不会阻止应用程序退出。

默认情况下,新线程是'Non Daemon'线程,由ExecutorService创建的线程也是如此。如果你想改变这一点,你必须创建自己的ThreadFactoryThreadFactory允许您手动为ExecutorService创建线程,当ExecutorService需要一个新线程时,它将被调用。下面是一个创建'Daemon'线程的例子:

public class DaemonThreadFactory implements ThreadFactory
{
    @Override
    public Thread newThread(final Runnable r)
    {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}
这可以通过创建执行器服务来使用:
ExecutorService service = Executors.newFixedThreadPool(100, new DaemonThreadFactory());

请注意,这也是给线程自定义名称的方式,这是非常有用的,因为许多日志框架记录线程名称(调试器显示它)。

如果你要这样做,在你的应用程序中,它会立即退出,因为你只创建'Daemon'线程,所以你必须保持另一个线程存活(这可以由另一个框架隐式地完成,例如,如果你有GUI)。

另一种方法是手动调用System.exit()。通常不建议在代码中调用System.exit()。主要是因为它不允许良好的重构、重用、测试,而且许多退出点使您的应用程序不可预测。为了避免这些问题,您可以创建一个回调函数来处理作业完成事件。在这个应用程序中,您调用System.exit(),您的测试代码或其他应用程序可以做其他事情。

在应用程序环境中,必须调用shutdown来确保ExecutorService启动的线程必须停止,并且不能再接受任何新的任务。否则JVM不会退出。

在Service的情况下,你应该在停止Service执行之前调用shutdown。例如,在web-app的情况下,ServletContextListenercontextDestroyed方法可以用来调用ExecutorServiceshutdown方法。这将确保任何现有的任务必须在突然终止申请之前完成,但不会接受新任务进行处理。

然而,我发现除非我调用executorService.shutdown();应用程序永远不会退出,

我认为我们不需要调用executorService.shutdown();让应用程序保持活力,对吗?

是的。除非调用executorService.shutdown()

,否则应用程序处于活动状态。

每个应用程序都应该有一个退出点。您可以在退出点调用shutdown。

如果你没有任何已知的退出点,ShutdownHook是解决问题的一种方法。但是你应该知道

在极少数情况下,虚拟机可能会中止,即停止运行而不彻底关闭

对于你所引用的例子,你可以用多种方式解决它(invokeAll, Future.get(), CountDownLatch等)。请看相关的SE问题

ExecutorService,如何等待所有任务完成

相关内容

  • 没有找到相关文章

最新更新