• Java多线程--创建和使用线程池


    使用线程池的目的

    • 线程是稀缺资源,不能频繁的创建

    • 解耦作用:线程的创建与执行完全分开,方便维护

    • 将其放入一个池子中,可以给其他任务进行复用

    优点

    • 降低资源消耗,通过重复利用已创建的线程来降低线程创建和销毁造成的消耗。

    • 提高相应速度,当任务到达时,任务可以不需要的等到线程创建就能立即执行。

    • 提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅仅会消耗系统资源,还会降低体统的稳定性,使用线程可以进行统一分配,调优和监控

    创建线程池的方式

     在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下三种:

    • Executors.newCachedThreadPool():无限线程池,线程池动态扩容

    • Executors.newFixedThreadPool(nThreads):创建固定大小的线程池

    • Executors.newSingleThreadExecutor():创建单个线程的线程池

    • Executors.newScheduledThreadPool():定时执行的线程池

     JDK1.8新增

    • Executors.newWorkStealingPool(): newWorkStealingPool适合使用在很耗时的操作,但是newWorkStealingPool不是ThreadPoolExecutor的扩展,它是新的线程池类ForkJoinPool的扩展,但是都是在统一的一个Executors类中实现,由于能够合理的使用CPU进行对任务操作(并行操作),所以适合使用在很耗时的任务中

    但是在阿里巴巴开发规约中对线程池的创建有以下几个强制要求:

    可以看到规约是不允许使用Executors直接创建线程池的,而要通过ThreadPoolExecutor的方式创建

    1 public static ExecutorService newCachedThreadPool() {
    2         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
    3                                       60L, TimeUnit.SECONDS,
    4                                       new SynchronousQueue<Runnable>());
    5 }

    我们看到这三种方式的源码也是通过ThreadPoolExecutor的方式来创建的,接下来我们看一下ThreadPoolExecutor的API

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler)

    这几个核心参数的作用:

    • corePoolSize 核心线程池大小

    • maximumPoolSize 为线程池最大线程大小

    • keepAliveTime线程池中超过 corePoolSize 数目的空闲线程最大存活时间

    • unit  keepAliveTime的时间单位
    • workQueue 用于存放任务的阻塞队列

    • threadFactory 线程工厂,可以自定义线程名称
    • handler 当队列和最大线程池都满了之后的拒绝策略

      • AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException 
      • CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度
      • DiscardPolicy:不能执行的任务将被删除 
      • DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

    工作原理

    • 当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程

    • 当线程池达到corePoolSize时,新提交任务将被放入 workQueue 中,等待线程池中任务调度执行

    • 当workQueue已满,且 maximumPoolSize 大于 corePoolSize 时,新提交任务会创建新线程执行任务 

    • 当提交任务数超过 maximumPoolSize 时,新提交任务由 RejectedExecutionHandler 处理

    • 当线程池中超过corePoolSize 线程,空闲时间达到 keepAliveTime 时,关闭空闲线程

    • 当设置allowCoreThreadTimeOut(true) 时,线程池中 corePoolSize 线程空闲时间达到 keepAliveTime 也将关闭

     线程池大小创建的原则

    • IO 密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2

    • CPU 密集型任务(大量复杂的运算)应当分配较少的线程,比如 CPU 个数相当的大小

    附:SpringBoot线程池工具类

  • 相关阅读:
    堆得简单介绍以及堆排序
    从交换两个变量的值来看程序员的“奇技淫巧”
    两道有意思的题目
    mac上使用brew
    安全考虑,binlog_row_image建议尽量使用FULL
    Python3.6新特性
    自动化测试基础篇--Selenium浏览器操作
    自动化测试基础篇--Selenium Xpath定位
    自动化测试基础篇--Selenium元素定位
    自动化测试基础篇--Selenium Python环境搭建
  • 原文地址:https://www.cnblogs.com/ding-dang/p/11145684.html
Copyright © 2020-2023  润新知