Java并发线程之线程池的知识总结

 更新时间:2021年01月26日 08:44:07   作者:入门小站  
这篇文章主要介绍了Java并发线程之线程池的知识总结,帮助大家更好的理解和学习Java并发线程的相关内容,感兴趣的朋友可以了解下

初始化线程池后,把任务丢进去,等待调度就可以了,使用起来比较方便。
JAVA中Thread是线程类,不建议直接使用Thread执行任务,在并发数量比较多的情况下,每个线程都是执行一个很短的时间就任务结束了,这样频繁创建线程会大大降低系统的效率,因为频繁的创建和销毁线程需要时间。而线程池可以复用,就是执行完一个任务,并不销毁,而是可以继续执行其它任务。

Thread的弊端

  • 每次new Thread() 创建对象,性能差。
  • 线程缺乏统一管理,可能无限制创建线程,相互竞争,有可能占用过多系统资源导致死机或OOM。
  • 不能多执行,定期执行,线程中断

线程池的优点

  • 重用存在的线程,减少对象创建,消亡的开销,性能佳,降低资源消耗。
  • 可以控制最大并发线程数,提高系统资源利用率,同时避免过多资源竞争,避免阻塞,提高响应速度。
  • 提供定时执行,定期执行,单线程,并发数控制等功能,以提高线程的可管理性。

阿里发布的 Java 开发手册中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池不会传入相关参数而使用默认值所以我们常常忽略了那些重要的参数(线程池大小、缓冲队列的类型等),而且默认使用的参数会导致资源浪费,不可取。

ThreadPoolExecutor介绍

构造函数和参数

java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类。

public class ThreadPoolExecutor extends AbstractExecutorService {
 /** 构造函数 1 */
 public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue) {}
        
 /** 构造函数 2 */
 public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory) {}
        
 /** 构造函数 3 */
 public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        RejectedExecutionHandler handler) {}
        
 /** 构造函数 4 */
 public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler) {}
}

ThreadPoolExecutor类中提供了四个构造方法,在构造函数4中,参数最多,通过观察其他3个构造函数,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

构造器中各个参数的含义

corePoolSize 核心线程池的大小,在创建了线程池后,默认情况下,线程池中没有任何的线程池,而是等任务过来了再去创建线程执行任务。除非调用了预创建线程的方法,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。当线程池中的线程数量到达corePoolSize后,就会把到达的任务放到缓存队列里面。

  • prestartCoreThread() : 预创建一个核心线程,使其闲置等待工作。
  • prestartAllCoreThreads() : 启动所有核心线程,导致它们空闲地等待工作。

maxnumPoolSize 线程池中最大的线程数,是一个非常重要的参数,它表示在线程池中最多能创建多少线程。
keepAliveTime 表示线程在没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,即当线程池中的线程数大于corePoolSize,如果一个线程的空闲时间达到keepAliveTime,则会终止直到线程池中的线程数量不大于corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中线程数不大于corePoolSize时,keepAliveTime参数也会启作用,直到线程池中的线程数为0。

unit 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性。

  • TimeUnit.DAYS : 以 天 为单位 ;
  • TimeUnit.HOURS : 以 小时 为单位 ;
  • TimeUnit.MINUTES : 以 分钟 为单位 ;
  • TimeUnit.SECONDS : 以 秒 为单位 ;
  • TimeUnit.MILLISECONDS : 以 毫秒 为单位 ;
  • TimeUnit.MICROSECONDS : 以 微秒 为单位 ;
  • TimeUnit.NANOSECONDS : 以 纳秒 为单位 ;

workQueue一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般有以下几种选择。

  • ArrayBlockingQueue:基于数组的先进先出队列,创建时必须指定大小。
  • LinkedBlockingQueue:基于链表的先进先出队列,若果创建时没有指定此队列的大小,则默认为Integer.MAX_VALUE
  • SynchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是直接新建一个线程来执行新的任务。

threadFactory线程工厂,主要用来创建线程。线程池最重要的一项工作,就是在满足某些条件情况下创建线程。在ThreadPoolExecutor线程池中,创建线程的操作时交给ThreadFactoty来完成。使用线程池,就必须要指定threadFactory。如果我们的构造器中没有指定使用ThreadFactory,这个时候ThreadPoolExecutor就会使用默认的ThreadFactory:DefaultThreadFactory
handler 在ThreadPoolExecutor线程池中还有一个重要的接口:RejectedExecutionHandler。当提交给线程池的某一个新任务无法直接被线程池中“核心线程”直接处理,又无法加入等待队列,也无法创建新的线程执行;又或者线程池已经调用shutdown()方法停止了工作;又或者线程池不是处于正常的工作状态;这时候ThreadPoolExecutor线程池会拒绝处理这个任务,触发创建ThreadPoolExecutor线程池时定义的RejectedExecutionHandler接口的实现,表示当拒绝处理任务时的策略,有以下四种取值,四种值都为其静态内部类:

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行新提交的任务。

ThreadPoolExecutor执行execute方法分下面4种情况

  • 如果当前运行的线程少于corePoolSize,则创建新的线程来执行任务(执行这一步骤需要获取全局锁)
  • 如果运行的线程等于或者多于corePoolSize,则将任务加入到BlockingQueue
  • 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步骤需要获取全局锁)
  • 如果创建新线程将当前运行的线程超出maxnumPoolSize,任务被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

以上就是Java并发线程之线程池的知识总结的详细内容,更多关于Java 线程池的资料请关注脚本之家其它相关文章!

相关文章

  • MybatisPlus查询条件为空字符串或null问题及解决

    MybatisPlus查询条件为空字符串或null问题及解决

    这篇文章主要介绍了MybatisPlus查询条件为空字符串或null问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

    解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

    本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常问题,通过排查和总结,作者发现使用MyBatis-Plus Boot Starter可以解决这个问题,文章详细对比了MyBatis-Plus Boot Starter和MyBatis Spring Boot Starter的功能和使用场景
    2025-01-01
  • java程序设计语言的优势及特点

    java程序设计语言的优势及特点

    在本篇文章里小编给大家分享的是一篇关于java程序设计语言的优势及特点的内容,需要的朋友们可以学习参考下。
    2020-02-02
  • Java中弱引用和软引用的区别以及虚引用和强引用介绍

    Java中弱引用和软引用的区别以及虚引用和强引用介绍

    很早Java API就添加了弱引用(WeakReference)和软引用(SoftReference),但并不是所有的程序员都熟悉这两个概念
    2014-04-04
  • 浅谈几种Java自定义异常处理方式

    浅谈几种Java自定义异常处理方式

    在Java中,异常是一种常见的处理机制,本文主要介绍了浅谈几种Java自定义异常处理方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 通过实例学习Spring @Required注释原理

    通过实例学习Spring @Required注释原理

    这篇文章主要介绍了通过实例学习Spring @Required注释原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 详解Spring-boot中读取config配置文件的两种方式

    详解Spring-boot中读取config配置文件的两种方式

    这篇文章主要介绍了详解Spring-boot中读取config配置文件的两种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • 利用java实现一个客户信息管理系统

    利用java实现一个客户信息管理系统

    这篇文章主要给大家介绍了关于利用java实现一个客户信息管理系统的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • springMVC导出word模板的方法

    springMVC导出word模板的方法

    这篇文章主要为大家详细介绍了springMVC导出word模板的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • idea如何解决maven依赖冲突

    idea如何解决maven依赖冲突

    这篇文章主要介绍了idea如何解决maven依赖冲突问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12

最新评论