tvi*_*alw 43 java spring threadpool
在Spring Web应用程序中,我有几个DAO和服务层bean.一个服务层bean具有带注释的@Async/@Scheduled方法.这些方法依赖于其他(自动装配的)bean.我在XML中配置了两个线程池:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="2" />
<property name="maxPoolSize" value="5" />
<property name="queueCapacity" value="5" />
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
<bean id="taskScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="poolSize" value="10" />
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作.我的问题是我无法完全关闭任务池.任务在数据库和文件系统上运行.当我停止Web应用程序时,它需要一些时间才能停止.这表明该waitForTasksToCompleteOnShutdown
物业有效.但是,我在日志中得到IllegalStateExceptions,表明某些bean已经被销毁但是一些工作任务线程仍在执行,并且它们因为依赖项被破坏而失败.
有一个JIRA问题可能是相关的:SPR-5387
我的问题是:有没有办法告诉Spring最后初始化任务执行程序/调度程序bean还是有办法告诉Spring先破坏它们吗?
我的理解是,销毁是以颠倒的初始顺序进行的.因此,最后初始化的bean将首先被销毁.如果首先销毁线程池bean,则所有当前正在执行的任务都将完成,并且仍然可以访问依赖bean.
我还尝试在引用我的服务bean的线程池上使用depends-on属性,该服务bean具有@Async和@Scheduled注释.好像它们从未执行过,我没有得到上下文初始化错误.我假设带注释的服务bean在某种程度上需要首先初始化这些线程池,如果我使用依赖,我会颠倒顺序并使它们不起作用.
sou*_*ica 54
两种方式:
有一个bean工具ApplicationListener<ContextClosedEvent>
. onApplicationEvent()
将在上下文之前调用并且所有bean都被销毁.
有一个bean实现生命周期或SmartLifecycle. stop()
将在上下文之前调用并且所有bean都被销毁.
无论哪种方式,您都可以在bean销毁机制发生之前关闭任务.
例如:
@Component
public class ContextClosedHandler implements ApplicationListener<ContextClosedEvent> {
@Autowired ThreadPoolTaskExecutor executor;
@Autowired ThreadPoolTaskScheduler scheduler;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
scheduler.shutdown();
executor.shutdown();
}
}
Run Code Online (Sandbox Code Playgroud)
(编辑:固定方法签名)
我已添加以下代码来终止您可以使用它的任务.您可以更改重试次数.
package com.xxx.test.schedulers;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import com.xxx.core.XProvLogger;
@Component
class ContextClosedHandler implements ApplicationListener<ContextClosedEvent> , ApplicationContextAware,BeanPostProcessor{
private ApplicationContext context;
public Logger logger = XProvLogger.getInstance().x;
public void onApplicationEvent(ContextClosedEvent event) {
Map<String, ThreadPoolTaskScheduler> schedulers = context.getBeansOfType(ThreadPoolTaskScheduler.class);
for (ThreadPoolTaskScheduler scheduler : schedulers.values()) {
scheduler.getScheduledExecutor().shutdown();
try {
scheduler.getScheduledExecutor().awaitTermination(20000, TimeUnit.MILLISECONDS);
if(scheduler.getScheduledExecutor().isTerminated() || scheduler.getScheduledExecutor().isShutdown())
logger.info("Scheduler "+scheduler.getThreadNamePrefix() + " has stoped");
else{
logger.info("Scheduler "+scheduler.getThreadNamePrefix() + " has not stoped normally and will be shut down immediately");
scheduler.getScheduledExecutor().shutdownNow();
logger.info("Scheduler "+scheduler.getThreadNamePrefix() + " has shut down immediately");
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Map<String, ThreadPoolTaskExecutor> executers = context.getBeansOfType(ThreadPoolTaskExecutor.class);
for (ThreadPoolTaskExecutor executor: executers.values()) {
int retryCount = 0;
while(executor.getActiveCount()>0 && ++retryCount<51){
try {
logger.info("Executer "+executor.getThreadNamePrefix()+" is still working with active " + executor.getActiveCount()+" work. Retry count is "+retryCount);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(!(retryCount<51))
logger.info("Executer "+executor.getThreadNamePrefix()+" is still working.Since Retry count exceeded max value "+retryCount+", will be killed immediately");
executor.shutdown();
logger.info("Executer "+executor.getThreadNamePrefix()+" with active " + executor.getActiveCount()+" work has killed");
}
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = context;
}
@Override
public Object postProcessAfterInitialization(Object object, String arg1)
throws BeansException {
return object;
}
@Override
public Object postProcessBeforeInitialization(Object object, String arg1)
throws BeansException {
if(object instanceof ThreadPoolTaskScheduler)
((ThreadPoolTaskScheduler)object).setWaitForTasksToCompleteOnShutdown(true);
if(object instanceof ThreadPoolTaskExecutor)
((ThreadPoolTaskExecutor)object).setWaitForTasksToCompleteOnShutdown(true);
return object;
}
Run Code Online (Sandbox Code Playgroud)
}
归档时间: |
|
查看次数: |
86346 次 |
最近记录: |