初学者很容易看错,如果没有看到spring或者JUC源码的人肯定是不太了解的。

ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JDK中的JUC。ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装处理。

自己在之前写多线程代码的时候都是这么玩的executor=Executors.newCachedThreadPool();但是有一次在大量数据的时候由于入库速度远大于出库速度导致内存急剧膨胀最后悲剧了重写代码,原来spring 早就给我们做好封装了。

来看一下ThreadPoolExecutor结构,祖类都是调用Executor接口:

再来看一下ThreadPoolTaskExecutor结构,祖类都是调用Executor接口:

再来看一下源码:

  1. public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements SchedulingTaskExecutor {
  2. private final Object poolSizeMonitor = new Object();
  3. private int corePoolSize = 1;
  4. private int maxPoolSize = 2147483647;
  5. private int keepAliveSeconds = 60;
  6. private boolean allowCoreThreadTimeOut = false;
  7. private int queueCapacity = 2147483647;
  8. private ThreadPoolExecutor threadPoolExecutor; //这里就用到了ThreadPoolExecutor
  1. //下面是设置完配置需要调用initialize方法初始化
  1. @Override
  2. protected ExecutorService initializeExecutor(
  3. ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
  4.  
  5. BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
  6. ThreadPoolExecutor executor = new ThreadPoolExecutor(
  7. this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
  8. queue, threadFactory, rejectedExecutionHandler);
  9. if (this.allowCoreThreadTimeOut) {
  10. executor.allowCoreThreadTimeOut(true);
  11. }
  12.  
  13. this.threadPoolExecutor = executor;
  14. return executor;
  15. }

这是ThreadPoolTaskExecutor用来初始化threadPoolExecutor的方法,BlockingQueue是一个阻塞队列,这个我们先不管。由于ThreadPoolTaskExecutor的实现方式完全是使用threadPoolExecutor进行实现,我们需要知道这个threadPoolExecutor的一些参数。

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize,
  3. long keepAliveTime,
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue,
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler) {
  8. if (corePoolSize < 0 ||
  9. maximumPoolSize <= 0 ||
  10. maximumPoolSize < corePoolSize ||
  11. keepAliveTime < 0)
  12. throw new IllegalArgumentException();
  13. if (workQueue == null || threadFactory == null || handler == null)
  14. throw new NullPointerException();
  15. this.corePoolSize = corePoolSize;
  16. this.maximumPoolSize = maximumPoolSize;
  17. this.workQueue = workQueue;
  18. this.keepAliveTime = unit.toNanos(keepAliveTime);
  19. this.threadFactory = threadFactory;
  20. this.handler = handler;
  21. }

     int corePoolSize:线程池维护线程的最小数量. 
  int maximumPoolSize:线程池维护线程的最大数量. 
  long keepAliveTime:空闲线程的存活时间. 
  TimeUnit unit: 时间单位,现有纳秒,微秒,毫秒,秒枚举值. 
  BlockingQueue<Runnable> workQueue:持有等待执行的任务队列. 
  RejectedExecutionHandler handler: 
  用来拒绝一个任务的执行,有两种情况会发生这种情况。 
  一是在execute方法中若addIfUnderMaximumPoolSize(command)为false,即线程池已经饱和; 
  二是在execute方法中, 发现runState!=RUNNING || poolSize == 0,即已经shutdown,就调用ensureQueuedTaskHandled(Runnable command),在该方法中有可能调用reject。

ThreadPoolExecutor池子的处理流程如下:  

1)当池子大小小于corePoolSize就新建线程,并处理请求

2)当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理

3)当workQueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理

4)另外,当池子的线程数大于corePoolSize的时候,多余的线程会等待keepAliveTime长的时间,如果无请求可处理就自行销毁

其会优先创建  CorePoolSiz 线程, 当继续增加线程时,先放入Queue中,当 CorePoolSiz  和 Queue 都满的时候,就增加创建新线程,当线程达到MaxPoolSize的时候,就会抛出错 误 org.springframework.core.task.TaskRejectedException

另外MaxPoolSize的设定如果比系统支持的线程数还要大时,会抛出java.lang.OutOfMemoryError: unable to create new native thread 异常。

  1. <!-- 异步线程池 -->
  2. <bean id="threadPool"
  3. class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  4. <!-- 核心线程数,默认为1 -->
  5. <property name="corePoolSize" value="3" />
  6. <!-- 最大线程数,默认为Integer.Max_value -->
  7. <property name="maxPoolSize" value="10" />
  8. <!-- 队列最大长度 >=mainExecutor.maxSize -->
  9. <property name="queueCapacity" value="25" />
  10. <!-- 线程池维护线程所允许的空闲时间 -->
  11. <property name="keepAliveSeconds" value="300" />
  12. <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->
  13. <property name="rejectedExecutionHandler">
  14.         <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
  15.         <!-- CallerRunsPolicy:若已达到待处理队列长度,将由主线程直接处理请求 -->
  16.         <!-- DiscardOldestPolicy:抛弃旧的任务;会导致被丢弃的任务无法再次被执行 -->
  17.         <!-- DiscardPolicy:抛弃当前任务;会导致被丢弃的任务无法再次被执行 -->
  18. <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
  19. </property>
  20. </bean>

Reject策略预定义有四种: 
(1)ThreadPoolExecutor.AbortPolicy策略,是默认的策略,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。 
(2)ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. 
(3)ThreadPoolExecutor.DiscardPolicy策略,不能执行的任务将被丢弃. 
(4)ThreadPoolExecutor.DiscardOldestPolicy策略,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程).

关于callable回调方法(因为为队列阻塞,如果到取值某个执行的值会等待执行完成)

  1. ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
  2. threadPoolTaskExecutor.setCorePoolSize(5);
  3. threadPoolTaskExecutor.setMaxPoolSize(50);
  4. threadPoolTaskExecutor.initialize();
  5.  
  6. List<String> paymentSeqNoList = new ArrayList<>();
  7. for (int i = 0; i <; i++) {
  8. paymentSeqNoList.add(String.valueOf(i));
  9. }
  10. Long startTime = System.currentTimeMillis();
  11. Map<String, FutureTask<String>> futureMap = new HashMap<String, FutureTask<String>>();
  12. //线程池提交返回
  13. for (String paymentSeqNo : paymentSeqNoList) {
  14. FutureTask<String> futureTask = new FutureTask<String>(new MyTestCallable(paymentSeqNo));
  15. futureMap.put(paymentSeqNo, futureTask);
  16. // submit提交执行
  17. threadPoolTaskExecutor.submit(futureTask);
  18. }
  19. Long endTime = System.currentTimeMillis();
  20. System.out.println("耗时1:" + (endTime - startTime));
  1. private static class MyTestCallable implements Callable<String> {
    private final String paymentSeqNo;
  2.  
  3. /**
    * 构造
    *
    * @param
    */
    public MyTestCallable(String paymentSeqNo) {
    this.paymentSeqNo = paymentSeqNo;
    }
  4.  
  5. /*
    * (non-Javadoc)
    * @see java.util.concurrent.Callable#call()
    */
    public String call() throws Exception {
    ControlRequest controlRequest = new ControlRequest(paymentSeqNo, CtrlType.RETRY, null);
    //System.out.println(controlRequest);
    return "成功";
    }
    }

关于callable回调值监听是否成功,JDK1.8 也开始支持guava方法了,guava有ListenableFuture 返回优化如下:

  1. Long startTime2 = System.currentTimeMillis();
  2. ListenableFuture<String> listenableFuture = null;
  3. for (String paymentSeqNo : paymentSeqNoList) {
  4. ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
  5. listenableFuture = executorService.submit(new Callable<String>() {
  6. @Override
  7. public String call() throws Exception {
  8. return "成功";
  9. }
  10. });
  11. }
    //监听事件
  12. Futures.addCallback(listenableFuture, new FutureCallback<String>() {
  13. @Override
  14. public void onSuccess(String result) {
  15. System.out.println("get listenable future's result with callback " + result);
  16. }
  17. @Override
  18. public void onFailure(Throwable t) {
  19. t.printStackTrace();
  20. }
  21. });
  22. Long endTime2 = System.currentTimeMillis();
  23. System.out.println("耗时2:" + (endTime2 - startTime2));

JAVA线程池学习,ThreadPoolTaskExecutor和ThreadPoolExecutor有何区别?的更多相关文章

  1. Java线程池学习

    Java线程池学习 Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java ...

  2. Java线程池学习总结

    一 使用线程池的好处 池化技术相比大家已经屡见不鲜了,线程池.数据库连接池.Http 连接池等等都是对这个思想的应用.池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率. 线程池提供了 ...

  3. Java线程池学习心得

    一.普通线程和线程池的对比 new Thread的弊端如下: a. 每次new Thread新建对象性能差.b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或o ...

  4. Java 线程池学习

    Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具.真正的线程池接口是ExecutorService. 下面这张图完整描述了线程 ...

  5. 【Java多线程】线程池学习

    Java线程池学习 众所周知,Java不仅提供了线程,也提供了线程池库给我们使用,那么今天来学学线程池的具体使用以及线程池基本实现原理分析. ThreadPoolExecutor ThreadPool ...

  6. 转:JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue

    从Java5开始,Java提供了自己的线程池.每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池.以下是我的学习过程. 首先是构 ...

  7. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  8. Java 线程池框架核心代码分析

    前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...

  9. 【Java线程池快速学习教程】

    1. Java线程池 线程池:顾名思义,用一个池子装载多个线程,使用池子去管理多个线程. 问题来源:应用大量通过new Thread()方法创建执行时间短的线程,较大的消耗系统资源并且系统的响应速度变 ...

随机推荐

  1. appium--xpath定位元素用法

    一.xpath的使用场景: 自动化测试中经常对元素进行操作时,如果存在id.name.content_desc时,可通过appium框架提供的方法find_element_by_id/name/tag ...

  2. 【深度学习篇】---CNN和RNN结合与对比,实例讲解

    一.前述 CNN和RNN几乎占据着深度学习的半壁江山,所以本文将着重讲解CNN+RNN的各种组合方式,以及CNN和RNN的对比. 二.CNN与RNN对比 1.CNN卷积神经网络与RNN递归神经网络直观 ...

  3. samba 基本配置及自定义控制

    Samba简介: Samba实现的是Linux和Windows之间的一种共享,为两种不同的操作系统架起了一座桥梁,使Linux系统和Windows系统之间能够实现互相通信,共享文件系统.打印机及其他资 ...

  4. 解决VS2019中.net core WPF 暂时无法使用 Designer 的临时方法

    目录 解决 VS2019 中.net core WPF 暂时无法使用 Designer 的临时方法 安装 vs 2019 professional/enterprise版本 在vs的设置里,勾选.NE ...

  5. TensorFlow从1到2(五)图片内容识别和自然语言语义识别

    Keras内置的预定义模型 上一节我们讲过了完整的保存模型及其训练完成的参数. Keras中使用这种方式,预置了多个著名的成熟神经网络模型.当然,这实际是Keras的功劳,并不适合算在TensorFl ...

  6. [译]PEP 342--增强型生成器:协程

    PEP原文 : https://www.python.org/dev/peps/pep-0342/ PEP标题: Coroutines via Enhanced Generators PEP作者: G ...

  7. 游戏UI框架设计(6): 消息传递中心

    游戏UI框架设计(6) --消息传递中心 最近一直忙于一个益智类游戏的研发工作,所以博客有段时间没有更新了.经过朋友的督促,决定这两天立刻完成最后的两篇博客讲解(UI框架).说起“消息传递中心”,或者 ...

  8. css中的position(定位)

    一.position语法与结构 position语法: position : static absolute relative position参数:static : 无特殊定位,对象遵循HTML定位 ...

  9. 小程序 wepy框架 + iview-weapp的用法

    最近在弄wepy的时候在想有没有什么ui比较合适一点的wepy的,也是在网上看了好久发现iview还不错.引用简单,上手超快,组件绚丽!当然,这里还介绍下微信官方建议的框架也是和不错的,有需要的可以看 ...

  10. HTML 练习绑定onclick事件

    方法一 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...