其他分享
首页 > 其他分享> > 线程池的那些事其一

线程池的那些事其一

作者:互联网

 

一,什么是线程池?

   简单来说,管理线程的池子。帮我们重复管理线程,避免创建大量的线程增加开销。

二,为什么用线程池?

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

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

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

三,什么时候用线程池?

  1. 单个任务处理时间比较短

  2. 需要处理的任务数量很大

四,解读线程池的原理

  A,七个核心参数

  1,corePoolSize,核心线程数量

  默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中

  2,maximumPoolSize,线程数最大值

  3,keepLiveTime,多长时间被回收

  默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

  4,timeUnit,设置keepLiveTime的时间单位,共7种单位:d, h, m, s, ms, mis, ns 

  5,workQueue,存放提交至线程池但未被执行的任务

  ArrayBlockingQueue(有界队列),是一个用数组实现的有界阻塞队列,按FIFO排序量。

  LinkedBlockingQueue(可设置容量队列),基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列

  DelayQueue(延迟队列),是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。

  PriorityBlockingQueue(优先级队列),是具有优先级的无界阻塞队列;

  SynchronousQueue(同步队列),一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

  6,threadFactory,创建线程的工厂

  用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字,code: new ThreadFactoryBuilder().setNameFormat("Hello-Engine").build();

  7,rejectedExecutionHandler,拒绝策略设置

  CallerRunsPolicy:只要线程池没关闭,就用调用者所在线程来运行任务

  AbortPolicy:直接抛RejectedExecutionException 异常

  DiscardPolicy:不处理,直接扔了

  DiscardOldestPolicy:把队列里待最久的那个任务扔了,并执行当前任务

  支持实现自己的 RejectedExecutionHandler 接口自定义策略,如记录日志类。

  B,线程池的状态

RUNNING

SHUTDOWN

STOP

TIDYING

TERMINATED

 

  C,任务执行流程

  1,execute()方法

  a,主要流程图如下:

  b,ThreadPoolExecutor执行流程

 

   c,源码解读

 2,submit()方法

ps: 线程池抛异常了,如何处理?

 

五,怎样使用线程池?

A,Executors常用方法及问题

 1,常用方法四种:

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

 

工作机制:

 

适用场景:用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

 

工作机制:

 

适用场景:用于串行执行任务的场景,一个任务一个任务地执行。

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

 

工作机制:

       

 

适用场景:用于并发执行大量短期的小任务。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

 

工作机制:

 

 

 2,使用Executors的问题, 来自阿里Java规范的建议:

       

B,自定义线程池

1,合理配置线程池

     通常我们是需要根据这批任务执行的性质来确定的。

     当然这些都是经验值,最好的方式还是根据实际情况测试得出最佳配置。

2,推荐使用Guava提供的ThreadFactoryBuilder来创建线程池
     

 

 

 

 

标签:其一,队列,创建,那些,corePoolSize,任务,线程,执行
来源: https://www.cnblogs.com/Jashinck/p/15115875.html