Java并发编程的艺术(十三)——Executor框架

378 阅读4分钟

Executor框架的两极调度模型

●HotSpot虚拟机将Java线程一对一映射为本地操作系统线程。

●在应用层,应用被分解为多个任务,并由Executor框架负责分配线程执行任务。

●在操作系统层,内核将这些线程映射到内核线程,并交由处理器。

Executor框架的结构

任务:任务需要实现Runnable接口或者Callable接口。

任务的执行:任务执行机制的核心接口为Executor,ExecutorService接口继承了Executor接口,Executor框架有两个关键类实现了ExecutorService接口,分别为ThreadPoolExecutor和ScheduledThreadPoolExecutor。

异步计算的结果:包括Future接口和Future接口的实现类FutureTask。


对上述接口和类的简介

●Executor接口是Executor框架的基础,它将任务的提交和执行分离开来。

●ThreadPoolExecutor是线程池的核心实现类,用来执行提交的任务。

●ScheduledThreadPoolExecutor是线程池的实现类,用来延迟提交任务的执行时间或者定期执行任务。

●Future接口及其实现类FutureTask表示异步计算的结果。

●实现了Runnable或Callable接口的实现类可被ThreadPoolExecutor或者ScheduledThreadPoolExecutor执行。

Executor框架的成员

Executor框架的主要成员有ThreadPoolExecutor、ScheduledThreadPoolExecutor、Future接口、Runnable接口、Callable接口、Executors。


  • 1.ThreadPoolExecutor:Executors可以创建三种类型的ThreadPoolExecutor,分别为SingleThreadExecutor、FixedThreadPool、CachedThreadPool。

    • ①.FixedThreadPool:该线程池里的线程数是固定的,它适用于需要限制当前线程数量的场景和负担比较重的服务器。
    • ②.SingleThreadExecutor:该线程池适用于需要按顺序执行任务,且在任意时间点只有一个线程在执行任务的场景。
    • ③CachedThreadPool:该线程池适用于执行很多短期异步任务,或者是负担较轻的服务器。

  • 2.ScheduledThreadPoolExecutor:Executors可以创建两种类型的ScheduledThreadPoolExecutor,分别为ScheduledThreadPoolExecutor、SingleThreadScheduledExecutor。
    • ①.ScheduledThreadPoolExecutor:适用于需要多个后台线程执行周期任务,且需要限制后台线程数量的场景。
    • ②SingleThreadScheduledExecutor:适用于需要单个后台线程执行周期任务,且保证任务按顺序执行的场景。

  • 3.Future接口:当调用ThreadPoolExecutor或者ScheduledThreadPoolExecutor的submit(……)方法时,会返回一个实现了Future接口的对象(即FutureTask对象)。

  • 4.Runnable接口和Callable接口:他们之间的区别是Runnable接口不会返回结果,Callable接口可以返回结果,但需要和FutureTask配合使用。

线程池详解

1.FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
  • ●FixedThreadPool是一种可重用、固定线程数的线程池。
  • ●FixedThreadPool的corePoolSize和maximumPoolSize大小均为nThreads。
  • ●FixedThreadPool的阻塞队列为LinkBlockingQueue,该队列为无界队列,故keepAliveTime、maximumPoolSize这两个参数无效。
  • ●由于队列无界,也就不需要饱和策略,handler这个参数也就没必要存在了。

2.SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor(){
    return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
  • ●SingleThreadExecutor的corePoolSize和maximumPoolSize均为1,其余参数和FixedThreadPool一样。
  • ●SingleThreadExecutor只会创建单个线程执行任务。
  • ●SingleThreadExecutor支持按顺序执行任务。

3.CachedThreadPool

public static ExecutorService newCachedThreadPool(){
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
}
  • ●CachedThreadPool的corePoolSize为0,maximumPoolSize可理解为无限大,故该线程池是无界的。
  • ●CachedThreadPool的keepAliveTime为60,表示线程池中空闲线程的存活时间为60秒,超过60秒后,空闲线程将被终止。
  • ●CachedThreadPool的阻塞队列是SynchronousQueue,该队列不存储元素,意味着每当新任务来临时,若线程池中没有空闲线程执行新任务,则会有新线程被创建出来执行任务。若新任务被提交的速度大于线程被执行完成的速度,就会不断有新线程产生,极端情况下会耗尽系统资源。

4.ScheduledThreadPoolExecutor

●ScheduledThreadPoolExecutor主要用来延迟执行任务,或者定期执行任务。


●ScheduledThreadPoolExecutor的任务队列为DelayQueue,是一个无界队列。


●ScheduledThreadPoolExecutor使用方法scheduledAtFixedRate()或者scheduledWithFixedDelay()提交任务时,会 向DelayQueue队列添加一个实现了RunnableScheduledFuture接口的ShceduledFutureTask。

  • SchduledFutureTask的3个主要参数:
  • 1.time:任务开始的时间
  • 2.sequenceNumber:任务被添加到队列中的序号
  • 3.period:任务执行的时间间隔。

●ScheduledThreadPoolExecutor的队列DelayQueue封装了一个PriorityQueue,它会根据time的大小对ShceduledFutureTask进行排序,若time相同则根据sequenceNumber排序。


●ScheduledThreadPoolExecutor执行任务的步骤如下

  • 1.线程从队列中获取已经到期的任务。
  • 2.执行任务后修改任务的time变量为下次要执行的时间。
  • 3.把任务重新返回到任务队列中。