Spring线程池ThreadPoolTaskExecutor

来源:互联网 发布:世辉律师事务所 知乎 编辑:程序博客网 时间:2024/06/09 19:46

配置

<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();        }    }}

于线程池中增加线程

@Resourceprivate 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,线程将被终止。这样,线程池可以动态的调整池中的线程数。

原创粉丝点击