配置
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数,维护线程的最少数量 -->
<property name="corePoolSize" value="5"/>
<!-- 最大线程数,维护线程的最大数量 -->
<property name="maxPoolSize" value="10"/>
<!-- 缓存队列 -->
<property name="queueCapacity" value="5"/>
<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
<property name="keepAliveSeconds" value="60"/>
<property name= "rejectedExecutionHandler" >
<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<bean class = "java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
定义Runnable 的实现类
public class DownLoadTask implements Runnable {
private static final Logger LOGGER = (Logger) LoggerFactory.getLogger(DownLoadTask.class);
//@Resource
private DownFileService downFileService;
private String taskName;
private Long taskId;
public DownLoadTask(String taskName, Long taskId, DownFileService downFileService){
this.taskName = taskName;
this.taskId = taskId;
this.downFileService = downFileService;
}
@Override
public void run() {
String[] headers = {"订单编号","订单金额","订单状态"};
try {
//File file = File.createTempFile(taskName, System.currentTimeMillis() + ".xls");
//String url = file.getCanonicalPath();
String url = "~/" + taskName + System.currentTimeMillis() + ".xls";
LOGGER.info("临时文件url--->>" + url + "任务id--->>" + taskId + "任务名称--->>" + taskName);
downFileService.exportFile("订单导出",headers,url,"",0,taskId, taskName);
//file.deleteOnExit();
}catch(Exception e) {
LOGGER.error("订单导出失败",e);
e.printStackTrace();
}
}
}
于线程池中增加线程
@Resource
private ThreadPoolTaskExecutor taskExecutor;
taskExecutor.execute(new DownLoadTask(taskName,taskId,downFileService));
原理
线程的创建、任务的提交、任务的执行、线程的销毁都是交由私有成员ThreadPoolExecutor来处理的
public void execute(Runnable task) {
ThreadPoolExecutor executor = this.getThreadPoolExecutor();
try {
executor.execute(task);
} catch (RejectedExecutionException var4) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, var4);
}
}
/*
* Support for execute().
*
* Method execute() and its helper methods handle the various
* cases encountered when new tasks are submitted. The main
* execute() method proceeds in 3 steps:
*
* 1. If it appears that fewer than corePoolSize threads are
* running, try to start a new thread with the given command as
* its first task. The check here errs on the side of caution.
* The call to addIfUnderCorePoolSize rechecks runState and pool
* size under lock (they change only under lock) so prevents false
* alarms that would add threads when it shouldn't, but may also
* fail to add them when they should. This is compensated within
* the following steps.
*
* 2. If a task can be successfully queued, then we are done, but
* still need to compensate for missing the fact that we should
* have added a thread (because existing ones died) or that
* shutdown occurred since entry into this method. So we recheck
* state and if necessary (in ensureQueuedTaskHandled) roll back
* the enqueuing if shut down, or start a new thread if there are
* none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. There's no guesswork here (addIfUnderMaximumPoolSize)
* since it is performed under lock. If it fails, we know we are
* shut down or saturated.
*
* The reason for taking this overall approach is to normally
* avoid holding mainLock during this method, which would be a
* serious scalability bottleneck. After warmup, almost all calls
* take step 2 in a way that entails no locking.
*/
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current <tt>RejectedExecutionHandler</tt>.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* <tt>RejectedExecutionHandler</tt>, if task cannot be accepted
* for execution
* @throws NullPointerException if command is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
1、当运行的线程数小于corePoolSize的时候 ,创建新的线程来处理被添加的任务。
2、如果线程数大于等于corePoolSize的时候,则将任务提交到workQueue队列中 。
3、如果此时线程池中的数量大于corePoolSize,且缓冲队列workQueue已满,则:
当线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务;
线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务。
即处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。