Executor 框架

Executor 框架结构

  • Executor 框架主要由 3 大部分组成如下。
    • 任务。包括被执行任务需要实现的接口:Runnable 接口Callable 接口
    • 任务的执行。包括任务执行机制的核心接口 Executor,以及继承自Executor 的 ExecutorService 接 口。Executor 框 架 有 两 个 关 键 类 实现 了 ExecutorService 接 口(ThreadPoolExecutorScheduledThreadPoolExecutor)。
    • 异步计算的结果。包括接口 Future实现 Future 接口的 FutureTask 类
    • Executor 框架的使用示意图

Executor 框架的成员

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

    • (1)ThreadPoolExecutor:

      • ThreadPoolExecutor 通常使用工厂类 Executors 来创建。Executors 可以创建 3 种类型的ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool 和 CachedThreadPool。

      • FixedThreadPool:固定数量的线程池,Executors 的 newFixedThreadPool 方法提供两个API

        • public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
          }
          
          public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>(),
                                          threadFactory);
          }
          
        • FixedThreadPool 适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器

        • FixedThreadPool 的 corePoolSize 和 maximumPoolSize 都被设置为创建是的指定参数 nThreads

          • 当线程池中的线程数大于 corePoolSize 时, keepAliveTime 为多余的空闲线程等待新任务的最长时间,超过时间多余的空闲线程将被终止。这里的 keepAliveTime 为0L,意味着多余的空闲线程会被立即终止
          • 如果线程数少于 corePoolSize ,则创建新的线程来执行任务(不管有没有空闲的线程,都会创建)
          • 线程池完成预热之后(当前运行的线程等于corePoolSize )将任务加入 LinkedBlockingQueue
        • FixedThreadPool 使用无界队列 LinkedBlockingQueue (队列容量为Integer.MAX_VALUE)对线程池带来的影响

          • 1)线程池线程数量到达 corePoolSize 后,新任务将在无界队列中等待,因此线程池的数量不会超过corePoolSize

          • 2)由1),使用无界队列时 maximumPoolSize 将是无效参数

          • 3)由于1)、2),使用无界队列时 keepAliveTime 将是一个无效参数。(无界队列不会满,将也不会出现已经创建的线程小于最大线程数,所以也不会有空闲线程 )

          • 4)由于使用无界队列,所以运行中的 FixedThreadPool (未执行两个 shutdown 方法)不会拒接任务(不会调用RejectedExecutionHandler.rejectedExecution 方法)

      • SingleThreadExecutor:单个线程的线程池,Executors 的 newSingleThreadExecutor 方法提供了两个API

        • public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
              (new ThreadPoolExecutor(1, 1,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>()));
          }
          
          public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
            return new FinalizableDelegatedExecutorService
              (new ThreadPoolExecutor(1, 1,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory));
          }
          
        • SingleThreadExecutor 适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景

        • SingleThreadExecutor 的 corePoolSize 和 maximumPoolSize 都被设置为1,其余参数都与FixedThreadPool 相同,也是使用了无界队列LinkedBlockingQueue作为线程池的工作队列。带来的影响跟 FixedThreadPool 相同

      • CachedThreadPool:大小无界的线程池,Executors 的 newCachedThreadPool 方法提供了两个API

        • public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
          }
          
          public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>(),
                                          threadFactory);
          }
          
        • CachedThreadPool 是大小无界的线程池,适用于执行很多短期的异步任务的小程序,或者是负载较轻的服务器

        • CachedThreadPool 的 corePoolSize 为0,但是 maximumPoolSize 被设置为Integer.MAX_VALUE ,所以可以说是 无界的,这里把 keepAliveTime 设置为 60L 意味着线程池中的空闲线程最长等待时间为60秒,超过将被终止

        • CachedThreadPool 使用的是没有容量的 SynchronousQueue 队列作为线程池的工作队列,但maximumPoolSize 是无界的。这意味着,如果主线程提交任务的速度高于 maximumPoolSize 中的线程处理任务的速度时,CachedThreadPool将会不断的创建新的线程,极端的情况下会因为创建过多的线程而耗尽CPU 和 内存的资源

    • (2)ScheduledThreadPoolExecutor (定时任务):

      • ScheduledThreadPoolExecutor任务传递图
      • ScheduledThreadPoolExecutor 通常使用 Executors 来创建。 可以创建两种类型的 ScheduledThreadPoolExecutor, 如下: 的 newScheduledThreadPool() 方法

        • ScheduledThreadPoolExecutor 包含若干线程的 ScheduledThreadPoolExecutor
        • SingleThreadScheduledExecutor 只包含一个线程的 ScheduledThreadPoolExecutor
      • 创建固定个数线程的 ScheduledThreadPoolExecutor API:

        • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){
            return new ScheduledThreadPoolExecutor(corePoolSize);
          }
          
          public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,                         ThreadFactory threadFactory) {
            return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
          }
          
          // --------------------
          
          public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
                  new DelayedWorkQueue());
          }
          
          public ScheduledThreadPoolExecutor(int corePoolSize,
                                                 ThreadFactory threadFactory) {
            super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
                  new DelayedWorkQueue(), threadFactory);
          }
          
        • ScheduledThreadPoolExecutor 适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。内部实际上是用延迟队列 DelayedWorkQueue 来实现

      • 创建单个线程的 SingleThreadScheduledExecutor 的 API:

        • public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
            return new DelegatedScheduledExecutorService
              (new ScheduledThreadPoolExecutor(1));
          }
          
          public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
            return new DelegatedScheduledExecutorService
              (new ScheduledThreadPoolExecutor(1, threadFactory));
          }
          
        • 内部实际上还是用 new ScheduledThreadPoolExecutor 的发那个是实现,但是包装了一层委托 DelegatedScheduledExecutorService

        • 适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容