Thread & ExecutorService & ThreadPoolExecutor 总览

简介: Thread & ExecutorService & ThreadPoolExecutor 总览ExecutorService类方法shutdown 允许已经提交的任务(尚未开始执行和已经开始执行...

Thread & ExecutorService & ThreadPoolExecutor 总览

ExecutorService

类方法

这里写图片描述

  1. shutdown
    允许已经提交的任务(尚未开始执行和已经开始执行的)继续执行
  2. shutdownNow
    尚未开始执行的任务不再执行,同时尝试终止正在执行的任务
  3. 无论是shutdown 还是shutdownNow,两个的执行都会阻止新的任务提交

  4. 一个ExecutorService一旦termination,表明没有正在执行的任务,没有等待执行的任务,也不会有新的任务可以被提交。

  5. 如果一个ExecutorService不再使用,应该调用shutdown方法来回收资源。

  6. submit方法(三个重载方法)

    返回的Future对象可以用来取消任务和等待任务执行完成
  7. invokeAny和invokeAll方法

    用户批量执行任务,
    invokeAny:会阻塞当前线程,直到某个任务完成。并返回这个任务相关的Future对象
    invokeAll:会阻塞当前线程,直到所有任务完成。
  8. 两阶段shutdown

    1. 先执行shutdown方法
    2. 调用awaitTermination方法
    3. 再调用shutdownNow方法
    void shutdownAndAwaitTermination(ExecutorService pool) {
       pool.shutdown(); // Disable new tasks from being submitted
       try {
         // Wait a while for existing tasks to terminate
         if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
           pool.shutdownNow(); // Cancel currently executing tasks
           // Wait a while for tasks to respond to being cancelled
           if (!pool.awaitTermination(60, TimeUnit.SECONDS))
               System.err.println("Pool did not terminate");
         }
       } catch (InterruptedException ie) {
         // (Re-)Cancel if current thread also interrupted
         pool.shutdownNow();
         // Preserve interrupt status
         Thread.currentThread().interrupt();
       }
    }
  9. isShutdown和isTerminated分别对应于两个状态:关闭状态,终结状态

Thread

  1. interrupt方法
    如果执行a.interrupt方法后,如果a线程(注意是a线程,不是调用线程)抛出了InterruptedException异常,那么a的中断状态会被清除。如果不是抛出InterruptedException异常,那么a的中断状态都会被设置。
  2. interrupted方法
    执行a.interrupted方法会返回a线程的中断状态,同时会清除a线程的中断状态
  3. isInterrupted方法
    执行a.interrupted方法会返回a线程的中断状态,不会清除a线程的中断状态

ThreadPoolExecutor

  1. core pool size 及 max pool size

    一个新的任务提交哪些情况下回创建新的线程:
        1. 已创建的的线程数小于corePoolSize(即便有线程是空闲的)
        2. 已创建的线程数大于corePoolSize小于maxPoolSize,同时任务队列已经满的情况下,也会创建新的线程
    
    可以动态改变这两个的值:setCorePoolSize  以及 setMaximumPoolSize
    
    如果corePoolSize==maxinumPoolSize,那么则创建了一个固定大小的线程池
  2. keep alive time

    如果已创建的线程大于了corePoolSize,并且如果有线程的空闲时间大于了keepAliveTime,那么这些线程会被kill掉直到剩下corePoolSize个线程。
    
    可以动态设置:setKeepAliveTime方法
    
    默认情况下keep-alive策略只会针对已创建线程数大于corePoolSize的情况下
    
    可以通过执行allowCoreThreadTimeOut(boolean)让keep-alive策略应用在已创建线程数小于corePoolSize的情况下。
  3. BlockingQueue

    1. 如果已创建线程数小于corePoolSize,那么会创建新的线程来执行当前提交的任务,而不是进入阻塞队列
    2. 如果已创建线程数大于等于corePoolSize,会尝试先进入阻塞队列,如果进入失败(其实就是队列已满),则会在maxPoolSize条件下创建新的线程来执行当前提交的任务。如果不满足maxPoolSize条件,那么就会执行 拒绝执行策略(默认的拒绝执行策略见下)
    3. 通常有三种入队列策略

      1. 直接传递给线程(Direct handoffs)

        比如:SychronousQueue
        
        感觉可以理解为这个入队列会总是失败,就相当于没有这个队列一样。这样就能在maxPoolSize条件下尽可能快的创建(或选择空闲的线程)来执行新提交的任务。
        
        如果提交的任务有互相的依赖性,可以考虑使用这种队列。
        
        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
      2. 无界队列(Unbounded Queue)

        比如:LinkedBlockingQueue
        
        可以理解为如果有任务需要入队列,那么总会入队成功。
        因此按照创建新线程的条件,理论上不会有超过corePoolSize个数的线程。也就是说理论上线程数最多为corePoolSize,因此maxPoolSize的设置也就显得没有意义了。
        
        如果提交的任务互相间没有依赖性,可以考虑使用这种队列
      3. 有界队列(Bounded Queue)

        比如:ArrayBlockingQueue
        
        如果使用有限个maxPoolSize,那么使用这种队列可以防止资源的耗尽。
        
        使用长队列和小的线程池,可以降低CPU使用率,降低系统资源的消耗,以及降低线程上下文切换的消耗,但是会导致低吞吐量。如果任务频繁的阻塞,系统可能会创建比允许的线程数多的线程。
        
        使用短队列和大的线程池,可以提高CPU使用率,但也有可能导致吞吐量下降。
  4. 拒绝执行策略(我自己的叫法,实际上就是 RejectedExceptionHandler )

    这里写图片描述

    1. ThreadPoolExecutor.AbortPolicy
      抛出RejectedExecutionException异常

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          throw new RejectedExecutionException("Task " + r.toString() +
                                               " rejected from " +
                                               e.toString());
      }
    2. ThreadPoolExecutor.CallerRunsPolicy
      在调用线程上执行(哪个线程提交的任务就哪个线程执行)

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          if (!e.isShutdown()) {
              r.run();
          }
      }
  5. ThreadPoolExecutor.DiscardPolicy
    直接放弃

    ```
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
    ```
    
    1. ThreadPoolExecutor.DiscardOldestPolicy
      放弃当前队列中第一个任务

      public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          if (!e.isShutdown()) {
              e.getQueue().poll();
              e.execute(r);
          }
      }
  6. Finalization

    一个在程序中不再被引用的线程池如果同时没有剩余的线程,那么这个线程池会被自动的shutdown.
    
    因此如果你想即便在忘记执行shutdown方法的时候仍能正常关闭线程池,那么建议设置一个有限的keepAliveTime(针对大于线程数大于corePoolSize的那些线程),同时也执行下 allowCoreThreadTimeOut(boolean) . 

欢迎关注公众号

目录
相关文章
|
SQL 运维 关系型数据库
在阿里云RDS(Relational Database Service)进行跨区域迁移
在阿里云RDS(Relational Database Service)进行跨区域迁移
412 2
|
Cloud Native Serverless 容器
袋鼠:云原生底层系统探索和实践
随着云计算的发展,云原生概念已经开始成为一种被广泛接受的开发理念。本文将概述我们面向云原生场景在底层技术方面做的探索以及实践。文章根据云栖大会系统软件专场内容整理,演讲者:韩伟东
4696 1
|
Kubernetes 关系型数据库 MySQL
ChaosBlade常见问题之数据库进行故障注入报错ibdata1文件异常如何解决
ChaosBlade 是一个开源的混沌工程实验工具,旨在通过模拟各种常见的硬件、软件、网络、应用等故障,帮助开发者在测试环境中验证系统的容错和自动恢复能力。以下是关于ChaosBlade的一些常见问题合集:
497 1
|
监控 网络协议 前端开发
WAF部署模式概念
WAF部署模式概念
|
前端开发 JavaScript Java
现代化软件开发中的前后端分离模式
随着互联网技术的快速发展,现代化软件开发中的前后端分离模式逐渐成为主流。本文将介绍前后端分离的概念和优势,以及如何在不同的技术栈中实现这种模式。通过前后端分离,可以提高开发效率、降低耦合性,并且更好地满足用户需求。
992 0
|
10月前
|
人工智能
一图看懂| 2024AI云重点产品技术升级
一图看懂| 2024AI云重点产品技术升级
|
9月前
|
SQL 自然语言处理 数据可视化
📊 Quick BI 真实体验评测:小白也能快速上手的数据分析工具!
作为一名软件开发工程师,我体验了阿里云的Quick BI工具。从申请试用账号到上传数据、创建数据集,再到搭建仪表板和使用智能小Q功能,整个过程流畅且简单易用。尤其对非专业数据分析人士来说,拖拽式设计和自然语言问数功能极大降低了操作门槛。虽然在试用入口明显度和复杂语义理解上还有提升空间,但整体体验令人满意。Quick BI让我改变了对数据分析的认知,值得推荐给需要快速制作报表的团队成员。
|
安全 数据挖掘
服务器数据恢复—RAID5阵列中两块硬盘离线导致阵列崩溃的数据恢复案例
服务器数据恢复环境: 两组分别由4块SAS接口硬盘组建的raid5阵列,两组raid5阵列划分LUN并由LVM管理,格式化为EXT3文件系统。 服务器故障: RAID5阵列中一块硬盘未知原因离线,热备盘自动激活上线替换离线硬盘。在热备盘上线过程中,raid5阵列中又有一块硬盘离线。热备盘同步失败,该raid阵列崩溃,LVM结构变得不完整,文件系统无法正常使用。
|
Java Maven
使用Java合并PDF文档
使用Java合并PDF文档
623 0
|
关系型数据库 分布式数据库 数据库
PolarDB,阿里云的开源分布式数据库,与微服务相结合,提供灵活扩展和高效管理解决方案。
【7月更文挑战第3天】PolarDB,阿里云的开源分布式数据库,与微服务相结合,提供灵活扩展和高效管理解决方案。通过数据分片和水平扩展支持微服务弹性,保证高可用性,且兼容MySQL协议,简化集成。示例展示了如何使用Spring Boot配置PolarDB,实现服务动态扩展。PolarDB缓解了微服务数据库挑战,加速了开发部署,为云原生应用奠定基础。
627 3