Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当tomcat关闭时,ExecutorService管理的线程会发生什么情况?_Java_Spring_Spring Boot - Fatal编程技术网

Java 当tomcat关闭时,ExecutorService管理的线程会发生什么情况?

Java 当tomcat关闭时,ExecutorService管理的线程会发生什么情况?,java,spring,spring-boot,Java,Spring,Spring Boot,我有一个在tomcat 7上运行的web应用程序(带有Spring/Spring boot)。有一些ExecutorService定义如下: public static final ExecutorService TEST_SERVICE = new ThreadPoolExecutor(10, 100, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPool

我有一个在tomcat 7上运行的web应用程序(带有Spring/Spring boot)。有一些ExecutorService定义如下:

    public static final ExecutorService TEST_SERVICE = new ThreadPoolExecutor(10, 100, 60L,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
public static final executor SERVICE TEST\u SERVICE=new ThreadPoolExecutor(1010060L,
TimeUnit.SECONDS,新的LinkedBlockingQueue(1000),新的ThreadPoolExecutor.CallerRunPolicy();
这些任务很重要,必须正确完成。我捕获异常并将其保存到db以供重试,如下所示:

try {
        ThreadPoolHolder.TEST_SERVICE.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    boolean isSuccess = false;
                    int tryCount = 0;
                    while (++tryCount < CAS_COUNT_LIMIT) {
                        isSuccess = doWork(param);
                        if (isSuccess) {
                            break;
                        }
                        Thread.sleep(1000);
                    }
                    if (!isSuccess) {
                        saveFail(param);
                    }
                } catch (Exception e) {
                    log.error("test error! param : {}", param, e);
                    saveFail(param);
                }
            }
        });
    } catch (Exception e) {
        log.error("test error! param:{}", param, e);
        saveFail(param);
    }
试试看{
ThreadPoolHolder.TEST_SERVICE.submit(new Runnable()){
@凌驾
公开募捐{
试一试{
布尔值isSuccess=false;
int tryCount=0;
而(++tryCount

那么,当tomcat关闭时,池中的线程(在队列中运行或等待)会发生什么情况?如何确保所有任务在关机前正确完成或保存到数据库以供重试?

Tomcat作为任何Java应用程序都不会结束,直到所有非daeon线程结束。上面示例中的ThreadPoolExecutor使用默认线程工厂,并将创建非守护进程线程。

Tomcat内置了线程泄漏检测,因此在取消部署应用程序时,您应该会收到一个错误。作为开发人员,您有责任将您创建的任何对象链接到web应用程序生命周期,这意味着您永远不应该拥有非常量的静态

如果您正在使用SpringBoot,那么您的Spring上下文已经链接到应用程序生命周期,因此最好的方法是将您的executor创建为SpringBean,并让Spring在应用程序停止时关闭它。下面是一个可以放入任何@Configuration类的示例

@Bean(destroyMethod = "shutdownNow", name = "MyExecutorService")
public ThreadPoolExecutor executor() {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L,
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), 
            new ThreadPoolExecutor.CallerRunsPolicy());
    return threadPoolExecutor;
}
记住,静态是有害的,您应该只对常量和可能不可变的对象使用静态

编辑

如果需要在任务处理完成之前阻止Tomcats关闭过程,则需要将执行器包装在一个组件中以获得更多的控制,如下所示

@Component
public class ExecutorWrapper implements DisposableBean {

    private final ThreadPoolExecutor threadPoolExecutor;

    public ExecutorWrapper() {
        threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public <T> Future<T> submit(Callable<T> task) {
        return threadPoolExecutor.submit(task);
    }

    public void submit(Runnable runnable) {
        threadPoolExecutor.submit(runnable);
    }

    @Override
    public void destroy() throws Exception {
        threadPoolExecutor.shutdown();
        boolean terminated = threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
        if (!terminated) {
            List<Runnable> runnables = threadPoolExecutor.shutdownNow();
            // log the runnables that were not executed
        }
    }
}
@组件
公共类ExecutorWrapper实现了DisposableBean{
私有最终ThreadPoolExecutor ThreadPoolExecutor;
公共包装器(){
threadPoolExecutor=新的threadPoolExecutor(1010060L,
TimeUnit.SECONDS,新的LinkedBlockingQueue(1000),新的ThreadPoolExecutor.CallerRunPolicy();
}
公共未来提交(可调用任务){
返回threadPoolExecutor.submit(任务);
}
公共作废提交(可运行可运行){
threadPoolExecutor.submit(可运行);
}
@凌驾
public void destroy()引发异常{
threadPoolExecutor.shutdown();
布尔终止=threadPoolExecutor.awaitTermination(1,TimeUnit.MINUTES);
如果(!终止){
List runnables=threadPoolExecutor.shutdownNow();
//记录未执行的可运行项
}
}
}
使用此代码,您首先调用
shutdown
,这样就不能提交新任务,然后等待执行者完成当前任务并排队。如果未及时完成,请调用
shutdownNow
中断正在运行的任务,并获取未处理任务的列表


注意:DisposableBean可以做到这一点,但最好的解决方案实际上是实现
SmartLifecycle
接口。您必须实现更多的方法,但您可以获得更大的控制,因为在所有bean被实例化并且整个bean层次结构连接在一起之前,不会启动任何线程,因此它甚至允许您指定组件启动的顺序。

谢谢!它真的更优雅。但是当tomcat关闭时会发生什么呢?我担心正在运行或在队列中的未完成任务。如何确保在tomcat重新启动时完成所有任务。
@Component
public class ExecutorWrapper implements DisposableBean {

    private final ThreadPoolExecutor threadPoolExecutor;

    public ExecutorWrapper() {
        threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60L,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public <T> Future<T> submit(Callable<T> task) {
        return threadPoolExecutor.submit(task);
    }

    public void submit(Runnable runnable) {
        threadPoolExecutor.submit(runnable);
    }

    @Override
    public void destroy() throws Exception {
        threadPoolExecutor.shutdown();
        boolean terminated = threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
        if (!terminated) {
            List<Runnable> runnables = threadPoolExecutor.shutdownNow();
            // log the runnables that were not executed
        }
    }
}