结论:Spring基于线程池的定时任务,线挰异常或内存溢出导致线程挂了,还会新启线程继续工作。
实例重现:
springMVC.properties
#the thread pool config thread.corePoolSize=3 thread.maxPoolSize=8 thread.keepAliveSeconds=6 thread.queueCapacity=2 timing.query.status.interval=3000
springMVC-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd "> <context:component-scan base-package="com.bijian.study"></context:component-scan> <!-- 系统配置文件 --> <context:property-placeholder location="classpath:springMVC.properties" /> <mvc:annotation-driven></mvc:annotation-driven> <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 核心线程数,默认为1 --> <property name="corePoolSize" value="${thread.corePoolSize}" /> <!-- 最大线程数,默认为Integer.MAX_VALUE --> <property name="maxPoolSize" value="${thread.maxPoolSize}" /> <!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE --> <property name="queueCapacity" value="${thread.queueCapacity}" /> <!-- 线程池维护线程所允许的空闲时间,默认为60s --> <property name="keepAliveSeconds" value="${thread.keepAliveSeconds}" /> <!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 --> <property name="rejectedExecutionHandler"> <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 --> <!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 --> <!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> </property> </bean> <task:scheduled-tasks> <!-- <task:scheduled ref="com.bijian.study.scheduled.TestScheduled" method="execute" cron="0 43 22 * * ?" /> --> <task:scheduled ref="com.bijian.study.scheduled.TestScheduled" method="execute" fixed-delay="${timing.query.status.interval}" /> </task:scheduled-tasks> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/views" /> <property name="suffix" value=".jsp" /> </bean> </beans>
ScheduledService.java
package com.bijian.study.service;
public interface ScheduledService {
void noNormalTest();
void normalTest();
}
ScheduledServiceImpl.java
package com.bijian.study.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.bijian.study.entity.Person;
import com.bijian.study.service.ScheduledService;
import com.bijian.study.util.JsonUtil;
@Service("scheduledService")
public class ScheduledServiceImpl implements ScheduledService {
private static Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);
private static int COUNT = 0;
@Override
public void noNormalTest() {
logger.info("entry ScheduledService noNormalTest:{}" ,"entry");
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
int j = 200/0;
List<Person> personList = new ArrayList<Person>(3);
personList.add(new Person("bijian", 10));
personList.add(new Person("lisi", 20));
personList.add(new Person("zhangshan", 30));
List<Person> personList2 = new ArrayList<Person>();
int i = 0;
int count = personList.size();
while(i < count) {
personList2.add(personList.get(i));
if(i == 2) {
personList2.clear();
}
}
}catch(Exception e) {
logger.error("noNormalTest Exception:{}", e);
}
logger.info("entry ScheduledService noNormalTest:{}" ,"exit");
}
@Override
public void normalTest() {
logger.info("entry ScheduledService normalTest:{}" ,"entry");
// try {
// //Thread.sleep(10000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
if(COUNT++ == 0) {
List<Person> personList = new ArrayList<Person>();
for(int i=0;i<1000000;i++) {
personList.add(new Person("bijian", 10));
personList.add(new Person("lisi", 20));
personList.add(new Person("zhangshan", 30));
}
logger.info("personList:{}", JsonUtil.toFullJson(personList));
}
}
}
BaseScheduled.java
package com.bijian.study.scheduled;
public interface BaseScheduled {
void execute();
}
TestScheduled.java
package com.bijian.study.scheduled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.bijian.study.controller.HelloController;
import com.bijian.study.service.ScheduledService;
@Service(value = "com.bijian.study.scheduled.TestScheduled")
public class TestScheduled implements BaseScheduled {
private static Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
@Qualifier("taskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private ScheduledService scheduledService;
private static int COUNT = 0;
@Override
public void execute() {
logger.info("enter TestScheduled");
if(0 == COUNT) {
threadPoolTaskExecutor.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
scheduledService.noNormalTest();
}
});
}else {
// class MyThread implements Runnable {
//
// private String name;
//
// public MyThread(String name) {
// this.name = name;
// }
//
// @Override
// public void run() {
try {
// logger.info("MyThread name:{}", name);
// try {
// Thread.sleep(30000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// scheduledService.normalTest();
}catch(Throwable e) {
logger.info("exception:{}", e);
}
// }
// }
threadPoolTaskExecutor.execute(new Runnable() {
@Override
public void run() {
scheduledService.normalTest();
}
});
}
COUNT ++;
logger.info("exit TestScheduled");
}
}
完整工程代码见附件《SpringMVC.zip》。