Java线程池介绍

Java线程池介绍

程序执行的过程中,可以单独的开启一个线程来处理任务,开启一个线程很简单,但是如果开启的线程过多,线程执行的时间很短,系统频繁的创建和销毁线程,很耗费时间,浪费系统的资源。于是就需要把线程管理起来,形成一个线程池。线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。它是将多个线程预先存储在一个“池子”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从“池子”内取出相应的线程执行对应的任务即可。有如下优点:

  • 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。

  • 提高响应速度:任务到达时,无需等待线程创建即可立即执行。

  • 提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。

  • 提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

Java线程池创建

image-20210207124955123

  • Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
  • Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
  • Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
  • Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
  • Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
  • Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
  • ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置。

线程池的执行流程如下图所示:

  1. 线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作 线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。

  2. 线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这 个工作队列里。如果工作队列满了,则进入下个流程。

  3. 线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程 来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

image-20210210090335431

ThreadPoolExecutor创建线程代码如下:

1
2
3
4
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
  • corePoolSize: 线程池核心线程数最大值

  • maximumPoolSize: 线程池最大线程数大小

  • keepAliveTime: 线程池中非核心线程空闲的存活时间大小

  • unit: 线程空闲存活时间单位

  • workQueue: 存放任务的阻塞队列

    1. ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。
    2. LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务。
    3. DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。
    4. PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列
    5. SynchronousQueue(同步队列)一个不存储元素的阻塞队列。
  • threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。

  • handler: 线城池的饱和策略事件,主要有四种类型。

    1. AbortPolicy(抛出一个异常,默认的)。
    2. DiscardPolicy(直接丢弃任务)。
    3. DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)。
    4. CallerRunsPolicy(交给线程池调用所在的线程进行处理)。

线程池状态

线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。

线程池各个状态切换框架图:

20190621155050101

  1. RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。线程池的初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0。

  2. SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。调用线程池的shutdown()方法时,线程池由RUNNING -> SHUTDOWN。

  3. STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。调用线程池的shutdownNow()方法时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

  4. TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。因为terminated()在ThreadPoolExecutor类中是空的,所以用户想在线程池变为TIDYING时进行相应的处理;可以通过重载terminated()函数来实现。当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

  5. TERMINATED:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。


Java线程池介绍
http://www.wangxiaohuan.com/2020/02/28/2020-02-28/
作者
吃素的左撇子
发布于
2020年2月28日
许可协议