线程池

Posted 小刘你最强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池相关的知识,希望对你有一定的参考价值。

线程池

线程池的优点/使用场景

  • 降低资源消耗.通过重复利用自己创建的线程降低线程创建和销毁造成的消耗.
  • 提高响应速度.当任务到达时,任务可以不需要等到线程的创建,就能立即执行.
  • 提高线程的可管理性.线程是稀缺资源,如果无限的创阿金,不仅会消耗资源,还会较低系统的稳定性,使用线程池可以进行统一分配,调优和监控.

Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor、Executors、ExecutorService、ThreadPoolExecutor 这几个类。

创建方式

jdk提供的4种线程池

ExecutorService pool1 = Executors.newSingleThreadExecutor();//创建单线程池

ExecutorService pool2 = Executors.newCachedThreadPool();//缓存的线程池

ExecutorService pool3 = Executors.newFixedThreadPool(4);//固定大小的线程池

ScheduledExecutorService pool4 = Executors.newScheduledThreadPool(4);//计划任务线程池

CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。

SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。

SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。

FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程

但是不建议在生产上使用,因为在生产上一定要指定线程池的阻塞队列和拒绝策略

通过 ThreadPoolExecutor创建

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

七大参数

  • corePoolSize 线程池中的常驻核心线程数
    创建线程池后,当有请求任务进来,就安排池中的线程去执行请求任务
    当线程池中的线程数目达到 corePoolSize 后,就会把到达的任务放到缓存队列中

  • maximumPoolSize
    线程池能够容纳同时执行的最大线程数,此值必须大于等于1

  • keepAliveTime 多余的空闲线程的存活时间
    当前线程池数量超过 corePoolSize 时,当空闲时间达到 keepAliveTime 值时,
    多余空闲线程会被销毁直到只剩下 corePoolSize 个线程为止

  • unit
    keepAliveTime 的单位

  • workQueue
    任务队列,被提交但尚未被执行的任务

  • threadFactory,表示生成线程池中工作线程的线程工厂<线程名字、线程序数…>,用于创建线程一般用默认的即可

  • handler,拒接策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时,如何拒绝新的任务

线程池的执行流程

在这里插入图片描述

  • 当调用 execute() 方法提交任务后,线程池先判断线程数是否达到了核心线程数(corePoolSize)。如果未达到线程数,则创建核心线程处理任务;否则,就执行下一步;
  • 接着线程池判断任务队列是否满了。如果没满,则将任务添加到任务队列中;否则,执行下一步;
  • 接着因为任务队列满了,线程池就判断线程数是否达到了最大线程数。如果未达到,则创建非核心线程处理任务;否则,就执行饱和策略,默认会抛出RejectedExecutionException异常。

拒绝策略

  • AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满
  • DisCardPolicy:不执行新任务,也不抛出异常
  • DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
  • CallerRunsPolicy:直接调用execute来执行当前任务

线程池的状态

线程池状态含义如下

• RUNNING 接受新任务并且处理阻塞队列里的任务

• SHUTDOWN :拒绝新任务但是处理阻塞队列里的任务

• STOP :拒绝新任务并且放弃阻塞队列里的任务,同时会中断正在处理的任务。

• TIDYING:所有任务都执行完(包含阻塞队列里面的任务)后,当前线程池活动线程,数为0,将要调用 terminated 方法

• TERMINATED:终止状态,terminated 方法调用完成以后的状态

线程池状态转换列举如下

• RUNNING -> SHUTDOWN 显式调用shutdown () 方法 或者隐式调用了 finalize()方法里面的 shutdown() 方法

• RUNNING或SHUTDOWN -> STOP 显式调用 shutdownNow() 方法

• SHUTDOWN ->TIDYING 当线程池和任务队列都为空时

• STOP -> TIDYING 当线程池为空时

• TIDYING -> TERMNATED terminated() hook 方法执行完成

关闭线程池

  • shutdown():线程池状态变为 SHUTDOWN,不会接收新任务,但已提交任务会执行完,此方法不会阻塞调用线程的执行
  • shutdownNow():线程池状态变为 STOP,不会接收新任务,会将队列中的任务返回,并用 interrupt 的方式中断正在执行的任务

线程池的工作队列

  • ArrayBlockingQueue:一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。
  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO(先进先出)排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞队列,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool()使用了这个队列。
  • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

以上是关于线程池的主要内容,如果未能解决你的问题,请参考以下文章

Java——线程池

Motan在服务provider端用于处理request的线程池

Java线程池详解

Java线程池详解

Java 线程池详解

线程池-实现一个取消选项