博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java~学习Executor框架, 了解ThreadPoolExecutor和ScheduledThreadPoolExecutor
阅读量:4050 次
发布时间:2019-05-25

本文共 4312 字,大约阅读时间需要 14 分钟。

文章目录

Executor框架

  • Java的线程既是工作单元,也是执行机制。从JDK 5开始,把工作单元与执行机制分离开 来。工作单元包括Runnable和Callable,而执行机制由Executor框架提供。

Runnable这个执行单元主要执行没有返回值的单元, 而Callable执行的是有返回值的单元

  • Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时, 为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃, 所以我们使用Executor框架提供的线程池去统一管理一些线程, 让这些线程去执行任务,而程序员只需要往线程池去增加任务即可。

Executor框架的结构

  • Executor框架主要由3大部分组成如下
  1. 任务: 被执行任务需要实现的接口:Runnable接口或Callable接口
  2. 任务的执行: 任务执行机制的核心接口Executor,以及继承自Executor的 ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口 (ThreadPoolExecutor和ScheduledThreadPoolExecutor)。
  3. 异步计算的结果: 包括接口Future和实现Future接口的FutureTask类。
    在这里插入图片描述
  • Executor是一个接口它是Executor框架的基础,它将任务的提交与任务的执行分离开 来。
  • ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
  • ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执 行命令。ScheduledThreadPoolExecutor比Timer更灵活,功能更强大。
  • Future接口和实现Future接口的FutureTask类,代表异步计算的结果。
  • Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或Scheduled- ThreadPoolExecutor执行。

Executor框架的成员

ThreadPoolExecutor

  • ThreadPoolExecutor通常使用工厂类Executors(也就是说Executors是一个工厂, 其内部有很多车间, 其中一个就是生产ThreadPoolExecutor的)来创建。Executors可以创建3种类型的 ThreadPoolExecutor、SingleThreadExecutor、FixedThreadPool和CachedThreadPool。
  1. FixedThreadPool。
    FixedThreadPool适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场 景,它适用于负载比较重的服务器。
  • 原理就是
    (1) 如果当前运行的线程数少于corePoolSize(核心线程的数量, 也就是允许多少个线程处于空闲状态),则创建新线程来执行任务。
    (2) 在线程池完成预热之后(当前运行的线程数等于corePoolSize),将任务加入 LinkedBlockingQueue。
    (3)一个线程执行完任务后,会在循环中反复从LinkedBlockingQueue获取任务来执行。 FixedThreadPool使用无界队列LinkedBlockingQueue作为线程池的工作队列(队列的容量为 Integer.MAX_VALUE)
  1. SingleThreadExecutor。
    SingleThreadExecutor适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
    SingleThreadExecutor的corePoolSize和maximumPoolSize(最大线程的数量)被设置为1。其他参数与 FixedThreadPool相同。SingleThreadExecutor使用无界队列LinkedBlockingQueue作为线程池的工 作队列(队列的容量为Integer.MAX_VALUE)
  2. CachedThreadPool。
  • CachedThreadPool是大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者 是负载较轻的服务器。
  • CachedThreadPool的corePoolSize被设置为0,即corePool为空;maximumPoolSize被设置为 Integer.MAX_VALUE,即maximumPool是无界的。这里把keepAliveTime设置为60L,意味着 CachedThreadPool中的空闲线程等待新任务的最长时间为60秒,空闲线程超过60秒后将会被 终止。
  • CachedThreadPool使用没有容量的SynchronousQueue作为线程池的工作队列,但 CachedThreadPool的maximumPool是无界的。这意味着,如果主线程提交任务的速度高于 maximumPool中线程处理任务的速度时,CachedThreadPool会不断创建新线程。极端情况下, CachedThreadPool会因为创建过多线程而耗尽CPU和内存资源。

ScheduledThreadPoolExecutor

  • ScheduledThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建2种类 型的ScheduledThreadPoolExecutor。
  1. ScheduledThreadPoolExecutor。
  • 包含若干个线程的ScheduledThreadPoolExecutor。适用于需要多个后台线程执行周期任务或者延时执行,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
  • 使用DelayQueue作为任务队列。DelayQueue封装了一个PriorityQueue,这个PriorityQueue会对队列中的Scheduled- FutureTask进行排序。排序时,time小的排在前面(时间早的任务将被先执行)。如果两个 ScheduledFutureTask的time相同,就比较sequenceNumber,sequenceNumber小的排在前面(也就 是说,如果两个任务的执行时间相同,那么先提交的任务将被先执行)。
  1. SingleThreadScheduledExecutor。
    只包含一个线程的ScheduledThreadPoolExecutor。 适用于需要单个后台线程执行周期任务或者延迟任务,同时需要保证顺序地执行各个任务的应用场景。

Future接口

  • Future接口和实现Future接口的FutureTask类用来表示异步计算的结果。
    当我们把Runnable 接口或Callable接口的实现类提交(submit)给ThreadPoolExecutor或 ScheduledThreadPoolExecutor时,ThreadPoolExecutor或ScheduledThreadPoolExecutor会向我们 返回一个FutureTask对象。
  • FutureTask可以处于下面3种状态。
  • 1)未启动。FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态。当创建一 个FutureTask,且没有执行FutureTask.run()方法之前,这个FutureTask处于未启动状态。
  • 2)已启动。FutureTask.run()方法被执行的过程中,FutureTask处于已启动状态。
  • 3)已完成。FutureTask.run()方法执行完后正常结束,或被取消(FutureTask.cancel(…)),或 执行FutureTask.run()方法时抛出异常而异常结束,FutureTask处于已完成状态。
  • 当FutureTask处于未启动或已启动状态时,执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或抛出异常。
  • FutureTask的实现基于AQS。java.util.concurrent中 的很多可阻塞类(比如ReentrantLock)都是基于AQS来实现的。AQS是一个同步框架,它提供通用机制来原子性管理同步状态、阻塞和唤醒线程,以及维护被阻塞线程的队列
  • 每一个基于AQS实现的同步器都会包含两种类型的操作,至少一个acquire操作。这个操作阻塞调用线程,除非/直到AQS的状态允许这个线程继续 执行。FutureTask的acquire操作为get()/get(long timeout,TimeUnit unit)方法调用。 至少一个release操作。这个操作改变AQS的状态,改变后的状态可允许一个或多个阻塞 线程被解除阻塞。FutureTask的release操作包括run()方法和cancel(…)方法。
  • 基于“复合优先于继承”的原则,FutureTask声明了一个内部私有的继承于AQS的子类 Sync,对FutureTask所有公有方法的调用都会委托给这个内部子类

Runnable接口和Callable接口

  • Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或Scheduled- ThreadPoolExecutor执行。
  • 它们之间的区别是Runnable不会返回结果,而Callable可以返回结 果。 除了可以自己创建实现Callable接口的对象外,还可以使用工厂类Executors来把一个 Runnable包装成一个Callable。 下面是Executors提供的,把一个Runnable包装成一个Callable的API。
    public static Callable callable(Runnable task)
  • 提交给 ThreadPoolExecutor或ScheduledThreadPoolExecutor执行时,submit(…)会向我们返回一个 FutureTask对象。我们可以执行FutureTask.get()方法来等待任务执行完成。当任务成功完成后 FutureTask.get()将返回该任务的结果。

转载地址:http://xjsci.baihongyu.com/

你可能感兴趣的文章
iOS app之间的跳转以及传参数
查看>>
iOS __block和__weak的区别
查看>>
Android(三)数据存储之XML解析技术
查看>>
Spring JTA应用之JOTM配置
查看>>
spring JdbcTemplate 的若干问题
查看>>
Servlet和JSP的线程安全问题
查看>>
GBK编码下jQuery Ajax中文乱码终极暴力解决方案
查看>>
Oracle 物化视图
查看>>
PHP那点小事--三元运算符
查看>>
解决国内NPM安装依赖速度慢问题
查看>>
Brackets安装及常用插件安装
查看>>
Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
查看>>
fastcgi_param 详解
查看>>
Nginx配置文件(nginx.conf)配置详解
查看>>
标记一下
查看>>
IP报文格式学习笔记
查看>>
autohotkey快捷键显示隐藏文件和文件扩展名
查看>>
Linux中的进程
查看>>
学习python(1)——环境与常识
查看>>
学习设计模式(3)——单例模式和类的成员函数中的静态变量的作用域
查看>>