线程池的一系列

本文源码的jar包是org\springframework\spring-context\3.2.14.RELEASE


1. 为什么要用线程池?

合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务

到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会

降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。(参见

ImportnNewhttp://www.importnew.com/17633.html))

然后我看到自己项目里面写的代码,就更能明白线程池的好处了:

代码注释掉的地方就是又起了一个线程去执行任务,实际上可以直接用线程池的,没有必要再去消耗资源去起一个线程,看到taskExecutor.execute(......),我就去了解了一下线

程池,看了一下它的源码,追本溯源。另外,用线程池的目的也是让主线程和子线程异步的去执行,互不影响,一边我去解析和落地我的数据,一边我去做返回。

package com.pingan.toa.asset.facade.creditcard.datarec.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import com.pingan.toa.asset.common.constant.CreditCardConstants;
import com.pingan.toa.asset.common.enums.ResponseTypeEnums;
import com.pingan.toa.asset.facade.creditcard.datarec.CustomerBasicInfoFacade;
import com.pingan.toa.asset.model.response.CommonResponse;
import com.pingan.toa.asset.service.creditcard.datarec.DataReceiveAndParseService;

@Component("customerInfoFacadeImpl")
public class CustomerBasicInfoFacadeImpl implements CustomerBasicInfoFacade {

	@Autowired
	private DataReceiveAndParseService dataReceiveAndParseService;
	
	@Autowired
	private ThreadPoolTaskExecutor taskExecutor;
	
	private static final Logger logger = LoggerFactory.getLogger(CustomerBasicInfoFacadeImpl.class);
	@Override
	public CommonResponse<String> postCustomerBasicInfo(final String allData) {
		
		logger.info("CustomerBasicInfoFacadeImpl postCustomerBasicInfo start....,allData:{}",allData);
		
		try{
			taskExecutor.execute(new Runnable() {
				@Override
				public void run() {
					logger.info("开始调用解析落地数据线程..........");
					dataReceiveAndParseService.parseDataAndSave(allData);	
					logger.info("结束调用解析落地数据线程..........");
				}
			});
		}catch(Exception e){
			
			logger.error("task run error,{}",e);
		
		}
		return new CommonResponse<String>(ResponseTypeEnums.SUCCESS, null,null, CreditCardConstants.DATA_SAVE_SUCCESS_MSG);
	}
	/*public class Task extends Thread{
		
		private String recData;
		
		public Task(String recData) {
			
			this.recData = recData;
		}
		@Override
		public void run() {
			
			logger.info("开始调用解析落地数据线程..........");
			dataReceiveAndParseService.parseDataAndSave(recData);
			try {
				sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			logger.info("结束调用解析落地数据线程..........");
			
		}
	}*/
}
 
 

2. taskExecutor.execute(...) 具体背后的原理是什么?

ctrl+F3看execute方法如下:

public void execute(Runnable task) {
		Executor executor = getThreadPoolExecutor();
		try {
			executor.execute(task);
		}
		catch (RejectedExecutionException ex) {
			throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
		}
}
那getThreadPoolExecutor()又是如何得到的呢?

        /**
	 * Return the underlying ThreadPoolExecutor for native access.
	 * @return the underlying ThreadPoolExecutor (never {@code null})
	 * @throws IllegalStateException if the ThreadPoolTaskExecutor hasn't been initialized yet
	 */
	public ThreadPoolExecutor getThreadPoolExecutor() throws IllegalStateException {
		Assert.state(this.threadPoolExecutor != null, "ThreadPoolTaskExecutor not initialized");
		return this.threadPoolExecutor;
	}
所以说ThreadPoolTaskExecutor会先进行一个初始化,然后调用 getThreadPoolExecutor()就可以得到一个Executor。那么我们来看一下它的初始化方法:

	protected ExecutorService initializeExecutor(
			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
		ThreadPoolExecutor executor  = new ThreadPoolExecutor(
				this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
				queue, threadFactory, rejectedExecutionHandler);
		if (this.allowCoreThreadTimeOut) {
			executor.allowCoreThreadTimeOut(true);
		}

		this.threadPoolExecutor = executor;
		return executor;
	}
首先对初始化方法里的new ThreadPoolExecutor(......)方法里的几个参数做一下说明:

/**
     * Creates a new <tt>ThreadPoolExecutor</tt> with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the
     * pool, even if they are idle.
     * @param maximumPoolSize the maximum number of threads to allow in the
     * pool.
     * @param keepAliveTime when the number of threads is greater than
     * the core, this is the maximum time that excess idle threads
     * will wait for new tasks before terminating.
     * @param unit the time unit for the keepAliveTime
     * argument.
     * @param workQueue the queue to use for holding tasks before they
     * are executed. This queue will hold only the <tt>Runnable</tt>
     * tasks submitted by the <tt>execute</tt> method.
     * @param threadFactory the factory to use when the executor
     * creates a new thread.
     * @param handler the handler to use when execution is blocked
     * because the thread bounds and queue capacities are reached.
     * @throws IllegalArgumentException if corePoolSize or
     * keepAliveTime less than zero, or if maximumPoolSize less than or
     * equal to zero, or if corePoolSize greater than maximumPoolSize.
     * @throws NullPointerException if <tt>workQueue</tt>
     * or <tt>threadFactory</tt> or <tt>handler</tt> are null.
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
corePoolSize:线程池的基本大小, 当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会

创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。(参见ImportnNewhttp://www.importnew.com/17633.html))

maximumPoolSize:线程池里最大线程数

keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大

这个时间,提高线程的利用率。(参见ImportnNewhttp://www.importnew.com/17633.html))

unitkeepAliveTime的单位

workQueue:是任务队列,当任务大于线程数时,要有个阻塞队列来保存这些等待执行的任务。BlockingQueue它有几种实现方式,分别是:

LinkedBlockingQueue,SynchronousQueue,ArrayBlockingQueue,PriorityBlockingQueue等,它们之间的区别已经该用何种队列可以去看一

下它们的源码,以及它里面的方法(参见http://blog.csdn.net/xin_jmail/article/details/26157971)。但可以看到源码里面创建队列的方法

createQueue(......)它里面却只用了两种队列LinkedBlockingQueue,SynchronousQueue,根据队列的容量来决定

/**
	 * Create the BlockingQueue to use for the ThreadPoolExecutor.
	 * <p>A LinkedBlockingQueue instance will be created for a positive
	 * capacity value; a SynchronousQueue else.
	 * @param queueCapacity the specified queue capacity
	 * @return the BlockingQueue instance
	 * @see java.util.concurrent.LinkedBlockingQueue
	 * @see java.util.concurrent.SynchronousQueue
	 */
	protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
		if (queueCapacity > 0) {
			return new LinkedBlockingQueue<Runnable>(queueCapacity);
		}
		else {
			return new SynchronousQueue<Runnable>();
		}
	}

ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常有帮助。(参见

ImportnNewhttp://www.importnew.com/17633.html))

RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略 

默认情况下是AbortPolicy,表示无法处理新任务时抛出异常(参见ImportnNewhttp://www.importnew.com/17633.html))

3. 那么像queueCapacity等这些参数是怎么配置的呢?

如果没有在xml文件里面配置的话,ThreadPoolTaskExecutor是有默认值的,如下:

        private int corePoolSize = 1;

	private int maxPoolSize = Integer.MAX_VALUE;

	private int keepAliveSeconds = 60;

	private boolean allowCoreThreadTimeOut = false;

	private int queueCapacity = Integer.MAX_VALUE;
可以看到 queueCapacity默认值是最大值,这显然是不合理的。那么我们需要在配置文件里进行设置:

http://www.springframework.org/schema/task/spring-task.xsd

<task:executor id="taskExecutor" pool-size="5-500" queue-capacity="10000"/>
先引入schema,再引入标签

那么spring究竟是怎么读到pool-size和queue-capacity这个值的呢,并且queue-capacity是怎么赋给queueCapacity的呢?

我们可以看一下源码,Parser for the 'executor' element of the 'task' namespace,就一目了然了

/**
 * Parser for the 'executor' element of the 'task' namespace.
 *
 * @author Mark Fisher
 * @author Juergen Hoeller
 * @since 3.0
 */
public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

	@Override
	protected String getBeanClassName(Element element) {
		return "org.springframework.scheduling.config.TaskExecutorFactoryBean";
	}

	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		String keepAliveSeconds = element.getAttribute("keep-alive");
		if (StringUtils.hasText(keepAliveSeconds)) {
			builder.addPropertyValue("keepAliveSeconds", keepAliveSeconds);
		}
		String queueCapacity = element.getAttribute("queue-capacity");
		if (StringUtils.hasText(queueCapacity)) {
			builder.addPropertyValue("queueCapacity", queueCapacity);
		}
		configureRejectionPolicy(element, builder);
		String poolSize = element.getAttribute("pool-size");
		if (StringUtils.hasText(poolSize)) {
			builder.addPropertyValue("poolSize", poolSize);
		}
	}

	private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
		String rejectionPolicy = element.getAttribute("rejection-policy");
		if (!StringUtils.hasText(rejectionPolicy)) {
			return;
		}
		String prefix = "java.util.concurrent.ThreadPoolExecutor.";
		if (builder.getRawBeanDefinition().getBeanClassName().contains("backport")) {
			prefix = "edu.emory.mathcs.backport." + prefix;
		}
		String policyClassName;
		if (rejectionPolicy.equals("ABORT")) {
			policyClassName = prefix + "AbortPolicy";
		}
		else if (rejectionPolicy.equals("CALLER_RUNS")) {
			policyClassName = prefix + "CallerRunsPolicy";
		}
		else if (rejectionPolicy.equals("DISCARD")) {
			policyClassName = prefix + "DiscardPolicy";
		}
		else if (rejectionPolicy.equals("DISCARD_OLDEST")) {
			policyClassName = prefix + "DiscardOldestPolicy";
		}
		else {
			policyClassName = rejectionPolicy;
		}
		builder.addPropertyValue("rejectedExecutionHandler", new RootBeanDefinition(policyClassName));
	}

}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值