线程池

2019/11/03 Java

本文主要介绍Java的线程池ThreadPoolExecutor,针对其使用原因,用法,用例做一些简单介绍。

目录

ThreadPoolExecutor

为什么使用线程池?

  • 当我们需要频繁的创建多线程来进行耗时操作的时候,如果使用new Thread()方式来创建之后销毁,对性能影响较大。线程间缺乏管理,可能无限的创建线程相互竞争。所以需要使用到线程池。

线程池好处?

  • 1.重用存在的线程,减少对象创建、销毁的性能开销。
  • 2.有效控制最大并发线程数,提高系统资源利用率。
  • 3.提供定时执行、定期执行、单线程、并发数控制。

ThreadPoolExecutor构造函数。

public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
  • corePoolSize : 线程池保留的核心线程数。线程池启动后默认为空,当任务来临时才会创建线程处理请求。
  • maximumPoolSize : 线程池最大线程数。如果线程池运行的线程数量小于corePoolSize,则创建新线程来处理请求。如果线程池运行的线程数大于corePoolSize,但是小于maximumPoolSize,那么任务会添加到任务队列中,当任务队列已满时线程池会创建线程处理任务。
  • keepAliveTime : 非核心线程处理完任务保留的时间,当时间到仍未有任务需要处理,则会销毁线程。
  • unit : 时间单位,keepAliveTime时间的单位,一般为TimeUnit.SECONDS.
  • workQueue : 任务队列。如果当前线程池达到核心线程数时,且当前线程都处于活跃状态时,则将新加入的任务放到此队列中。
  • threadFactory : 线程工厂,让用户可以定制线程的创建过程,通常不需要设置。
  • Handler : 拒绝策略。

线程池拒绝策略

Java线程池提供了四种拒绝策略,如果需要自定义拒绝策略,则可以实现接口RejectedExecutionHandler 。四种拒绝策略如下:

  • CallerRunsPolicy 当触发拒绝策略时,除非线程池关闭,那么就会一直调用线程运行任务。一般并发量比较小,性能要求不高,不允许失败。
  • AbortPolicy 线程池默认拒绝策略。丢弃任务,并抛异常RejectedExecutionException
  • DiscardPolicy 直接丢弃任务
  • DiscardOldestPolicy 除非线程池关闭,否则丢弃最早的任务,并将新任务加入。

Summary

  • 所以线程池的优先级为:1. CoreThread 2. workQueue 3. new thread 4. reject。线程池先创建核心线程数corePoolSize的线程,任务先通过核心线程来执行。当核心线程无空闲的时候,新任务便添加至任务队列中。任务队列添加满后,线程池才新建新线程数直到maximumPoolSize。在所有线程都处于运行状态时,如果再有新任务,则选择执行相对应的拒绝策略。该流程中含有两个缓冲策略,一个是任务队列workQueue,一个是maximumPoolSize。线程池总体思想为一种池化产物,简单来说为:满而不损则溢,盈而不持则倾,是生产者-消费者模型。

  • 阿里Java开发手册建议, 线程池不允许使用Excutors创建,而是通过ThreadPoolExcutor的方式创建,这样的处理方式可以规避资源耗尽的风险。

  • 在构建线程池时,需要根据实际业务需求来定义maximumPoolSizekeepAliveTimeHandlermaximumPoolSize需要根据当前设备CPU的可用线程数来设定,而线程存活时间及拒绝策略则要根据并发量及性能要求来trade off。

引用

Search

    Table of Contents