zoukankan      html  css  js  c++  java
  • ThreadPoolTaskExecutor源码

    前言

    最近在面试中被问到了这个区别,没回答得很好,刚好这一块涉及到了spring的异步任务,就好好的来总结一下关于源码的一些东西。

    正文

    这个类是spring框架的下的一个类,这个类是对jdk自带的ThreadPoolExecutor进行了封装。 他的底层实现还是jdkThreadPoolExecutor

    构造方法

    这个类没有构造方法,使用默认的构造方法。

    属性

    
        // 监视器锁,synchronized使用该对象作为锁对象
        private final Object poolSizeMonitor = new Object();
        // 核心线程数量
    	private int corePoolSize = 1;
        // 最大线程数量
    	private int maxPoolSize = Integer.MAX_VALUE;
        // 线程存活时间
    	private int keepAliveSeconds = 60;
        // 队列初始化容量
    	private int queueCapacity = Integer.MAX_VALUE;
        // 核心线程数是否有空闲时间
    	private boolean allowCoreThreadTimeOut = false;
    	@Nullable //任务装饰器
    	private TaskDecorator taskDecorator;
    	@Nullable // 线程池
    	private ThreadPoolExecutor threadPoolExecutor;
    	
    

    以上参数是ThreadPoolTaskExecutor的默认参数。
    上面的参数相对ThreadPoolExecutor来说,少了拒绝策略参数。
    当然,ThreadPoolTaskExecutor还提供了上面参数的setget方法。

    方法

    ThreadPoolTaskExecutor执行任务都是调用的ThreadPoolExecutor来执行任务的,这里就不细说了。

    initializeExecutor方法

    这个方法被ThreadPoolTaskExecutor进行了重写,而这个方法是ExecutorConfigurationSupport类的一个接口。

    
        @Override
    	protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
    	    // 创建阻塞队列
    		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
    		ThreadPoolExecutor executor;
    		// 若装饰器不为空,重写ThreadPoolExecutor的execute方法,对任务进行装饰(装饰器模式)
    		if (this.taskDecorator != null) { 
    			executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,queue, threadFactory, rejectedExecutionHandler) {
    				@Override
    				public void execute(Runnable command) {
    					Runnable decorated = taskDecorator.decorate(command);
    					if (decorated != command) {
    						decoratedTaskMap.put(decorated, command);
    					}
    					super.execute(decorated);
    				}
    			};
    		}
    		else {
    			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;
    	}
    	
    

    上面的源码也不算难,看过ThreadPoolExecutor源码的就很容易看出来了。
    最开始提到的拒绝策略参数是在这里传入的,除此之外的参数都是ThreadPoolTaskExecutor中有的。

    这个方法还用到了装饰器模式,这里可以标注一下,装饰器实现的的源码也比较简单。

    下面来看看父类ExecutorConfigurationSupport中该接口的源码吧:

    
        // 父类中的接口
        protected abstract ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);
    
        // 该方法调用了initializeExecutor方法
        public void initialize() {
    		if (logger.isInfoEnabled()) {
    			logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
    		}
    		if (!this.threadNamePrefixSet && this.beanName != null) {
    			setThreadNamePrefix(this.beanName + "-");
    		}
    		// 这里的拒绝策略默认使用new ThreadPoolExecutor.AbortPolicy();
    		this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
    	}
    	// 看到这个方法,就知道该方法在bean初始化完成后会被调用
    	@Override
    	public void afterPropertiesSet() {
    	    // 调用initialize方法
    		initialize();
    	}
    	
    

    ExecutorConfigurationSupport实现InitializingBean接口的afterPropertiesSet方法。
    该方法会在bean被容器初始化完成后调用。
    也就是ThreadPoolTaskExecutorinitializeExecutor方法是容器初始化该bean后会自动调用该方法,所以不用手动调用。

    总结:
    我们虽然在创建ThreadPoolTaskExecutor时,未创建ThreadPoolExecutor
    网上有的博客还说在创建ThreadPoolTaskExecutor时,需要手动去调用initializeExecutor方法,个人觉得这个是有歧义的,
    具体需不需要手动调用初始化方法,是要看自己怎么去利用ThreadPoolTaskExecutor的,假如是将其作为bean放入容器的,则不需要手动调用。若未加入容器,二十自己手动进行管理,则需要手动调用。

    下面是createQueue方法代码

    
        protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
    		if (queueCapacity > 0) {
    			return new LinkedBlockingQueue<>(queueCapacity);
    		}
    		else {
    			return new SynchronousQueue<>();
    		}
    	}
    	
    

    这里需要注意的是,ThreadPoolTaskExecutor队列默认参数是Integer.MAX_VALUE,这里具体怎么设置就根据自己的业务而定了

    总结

    ThreadPoolTaskExecutorThreadPoolExecutor的区别?

    1. ThreadPoolExecutor是jdk自带的线程池,ThreadPoolTaskExecutor是spring的
    2. ThreadPoolTaskExecutorThreadPoolExecutor进行了封装,具体任务自行还是使用的ThreadPoolExecutor
    3. 注意ThreadPoolTaskExecutor的一些默认参数,是需要修改的。
    4. 若是自定义的ThreadPoolTaskExecutor实例,且未加入容器中,则需要手动调用初始化方法,若是放入容器中的,则不需要手动调用初始化方法。
    5. ThreadPoolTaskExecutor使用了装饰器模式来对任务进行装饰,可以参考,面试中也有可能会遇到相关的问题
  • 相关阅读:
    linux系统中如何进入退出vim编辑器,方法及区别
    [转]JAVA的动态代理机制及Spring的实现方式
    mybaties 缓存
    全面分析 Spring 的编程式事务管理及声明式事务管理
    面试(4)-spring-Spring面试题和答案
    vector的多套遍历方案
    【QT】QT下载与安装
    【QT】无需写connect代码关联信号和槽函数
    【QT】第一个QT程序(点击按钮,显示特定文本)
    【QT】error: 'SIGNAL' was not declared in this scope
  • 原文地址:https://www.cnblogs.com/guoyuchuan/p/14965682.html
Copyright © 2011-2022 走看看