当executorService.shutdown(); 应该叫

Jas*_*son 4 java multithreading threadpool

我们有一个服务方法GetDataParallel(),它当前可能被许多客户端调用,我们使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Tim*_*eau 5

通常,在应用程序退出时关闭ExecutorService - 大多数应用程序具有某种生命周期和关闭顺序.如果您希望应用程序在主线程完成任何必须执行的操作时退出,那么您希望在其工作完成时将其关闭(这意味着有一个明确定义的点,它的工作已完成,并且您可以告诉它何时是).

服务器端框架经常具有生命周期方法,您可以将其挂钩以检测代码何时关闭并彻底退出.或者您可以使用VM关闭挂钩(可能延迟关闭直到所有当前排队的作业完成),这样无论代码导致程序退出,您的清理代码都将运行.

一般来说,如果没有框架提供的退出点,最好创建一个明确定义的退出点 - 它允许您拥有一个可以干净地卸载的应用程序(并且可能重新加载更新的配置)而不必使用VM完全关闭 - 我已经使用了这个技巧,可以让服务器应用程序自行重新配置,并在零响应Unix信号的情况下重新加载零停机时间.

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

顺便说一句,为了与其他响应者相矛盾,ExecutorService 可以使用守护程序线程 - 您可以提供一个ThreadFactory,在您启动它们之前配置您想要的线程.但是我鼓励你不要使用守护程序线程并在一个明确定义的位置显式关闭线程池 - 这不是典型的做法,但它都意味着你的代码有可能被干净地关闭,它会鼓励你思考生命周期,这可能会带来更好的代码.


Thi*_*ler 4

Java 中有两种类型的线程(当然取决于您如何看待它们)。“用户”线程和“守护程序”线程。您的申请因以下情况之一而结束:

  1. 你打电话System.exit()
  2. 您的应用程序中没有User剩余线程。这里对此进行解释。

请注意,您的main函数是由 JVM 在“用户”线程上执行的,这意味着只要您尚未完成您的main函数。大多数多线程应用程序只会运行 main 函数来启动所需的所有线程。

守护线程背后的想法是,您可以(定期)执行某些操作,但如果所有其他任务都已完成,则不会阻止应用程序退出。

默认情况下,新线程是“非守护程序”线程,您的ExecutorService. 如果您想更改此设置,则必须创建自己的ThreadFactory. AThreadFactory允许您手动为ExecutorService创建线程,当ExecutorService需要新线程时它将被调用。以下是创建“守护进程”线程的示例:

public class DaemonThreadFactory implements ThreadFactory
{

    @Override
    public Thread newThread(final Runnable r)
    {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后可以通过创建执行器服务来使用它:

ExecutorService service = Executors.newFixedThreadPool(100, new DaemonThreadFactory());
Run Code Online (Sandbox Code Playgroud)

请注意,这也是为线程提供自定义名称的方法,这非常有用,因为许多 logframeworks 都会记录线程名称(并且调试器会显示它)。

如果您要在应用程序中执行此操作,它会立即退出,因为您只创建“守护进程”线程,因此您必须保持另一个线程处于活动状态(这可以由另一个框架隐式完成,例如,如果您有图形用户界面)。

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