线程池详解

5 篇文章 0 订阅
1 篇文章 0 订阅

在了解线程池之前,要先理解一个问题

为什么要使用线程池

a.线程池可以更加有效的利用cpu资源,减少创建线程,销毁线程带来的多余的开销

b.线程池能控制线程的并发数目,管理线程并发问题

c.线程池用一些其他的特性,延时调度执行,例如:scheduleThreadPool能使线程定时调度执行

 

我们先看下线程池的构造方法:

int corePoolSize => 该线程池中核心线程数

       核心线程指的是在线程池中不会被回收的线程,当然也可以通过设置allowCoreThreadTimeOut 为true将超过keepAliveTime空闲的核心线程销毁。

int maximumPoolSize => 最大线程数

       最大线程是指核心线程和非核心线程的最大容量,即线程池的最大值

long keepAliveTime => 闲置存活时间

       一般是指非核心线程的空闲存活时间,但是allowCoreThreadTimeOut 为true时也适用于核心线程

TimeUnit unit =>闲置存活时间的单位(枚举类型)

       NANOSECONDS : 1微毫秒 = 1微秒 / 1000,MICROSECONDS : 1微秒 = 1毫秒 / 1000,MILLISECONDS : 1毫秒 = 1秒 /1000,SECONDS : 秒,MINUTES : 分,HOURS : 小时,DAYS : 天

BlockingQueue<Runnable> workQueue =>线程池的任务队列

       1.1 直接提交的任务队列(SynchronousQueue)

       (1)      SynchronousQueue没有容量。

       (2)      提交的任务不会被真实的保存在队列中,而总是将新任务提交给线程执行。如果没有空闲的线程,则尝试创建新的线程。如果线程数大于最大值maximumPoolSize,则执行拒绝策略。

       1.2 有界的任务队列(ArrayBlockingQueue)

       (1)      创建队列时,指定队列的最大容量。

       (2)      若有新的任务要执行,如果线程池中的线程数小于corePoolSize,则会优先创建新的线程。若大于corePoolSize,则会将新任务加入到等待队列中。

       (3)      若等待队列已满,无法加入。如果总线程数不大于线程数最大值maximumPoolSize,则创建新的线程执行任务。若大于maximumPoolSize,则执行拒绝策略。

       1.3 无界的任务队列(LinkedBlockingQueue)

       (1)      与有界队列相比,除非系统资源耗尽,否则不存在任务入队失败的情况。

       (2)      若有新的任务要执行,如果线程池中的线程数小于corePoolSize,线程池会创建新的线程。若大于corePoolSize,此时又没有空闲的线程资源,则任务直接进入等待队列。

       (3)      当线程池中的线程数达到corePoolSize后,线程池不会创建新的线程。

       (4)      若任务创建和处理的速度差异很大,无界队列将保持快速增长,直到耗尽系统内存。

       (5)     使用无界队列将导致在所有 corePoolSize 线程都忙时,新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize(因此,maximumPoolSize 的值也就无效了)。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

       1.4 优先任务队列(PriorityBlockingQueue)

       (1)      带有执行优先级的队列。是一个特殊的无界队列。

       (2)      ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出算法来处理任务。而PriorityBlockingQueue可根据任务自身的优先级顺序先后执行(总是确保高优先级的任务先执行)。

       1.5 延迟队列(DelayQueue)

       队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

ThreadFactory =>线程工厂用来产生线程

       就是一个接口,newThread方法就是用来生产线程的,子类需要实现这个方法来根据自己规则生产相应的线程。

RejectedExecutionHandler handler =>拒绝策略

   当线程池线程大于最大线程容量时,执行拒绝策略,目前

  • AbortPolicy
  • 丢掉这个任务并且抛出RejectedExecutionException异常
  • DiscardPolicy
  • 会直接丢掉这个任务并且不会有任何异常
  • DiscardOldestPolicy
  • 会将最早进入队列的任务删掉腾出空间,再尝试加入队列
  • CallerRunsPolicy
  • 如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行
  • 自定义
  • 自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口,并且实现rejectedExecution方法就可以了

 

ThreadPoolExecutor的策略

       线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务

       线程数量达到了corePools,则将任务移入队列等待

       队列已满,新建线程(非核心线程)执行任务

       队列已满,总线程数又达到了maximumPoolSize,就会由上面那位星期天(RejectedExecutionHandler)抛出异常

 

常见四种线程池

CachedThreadPool()

       使用 直接提交的任务队列(SynchronousQueue)

可缓存线程池:

  1. 线程数无限制
  2. 有空闲线程则复用空闲线程,若无空闲线程则新建线程
  3. 一定程序减少频繁创建/销毁线程,减少系统开销

创建方法:

       ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

源码:

FixedThreadPool()

       使用 无界的任务队列(LinkedBlockingQueue)

定长线程池:

  1. 可控制线程最大并发数(同时执行的线程数)
  2. 超出的线程会在队列中等待

创建方法:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);

源码:

ScheduledThreadPool()

使用 延迟队列(DelayQueue)

定长线程池:

  1. 支持定时及周期性任务执行。

创建方法:

 ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

源码:

SingleThreadExecutor()

使用 无界的任务队列(LinkedBlockingQueue)

单线程化的线程池:

  1. 有且仅有一个工作线程执行任务
  2. 所有任务按照指定顺序执行,即遵循队列的入队出队规则

创建方法:

ExecutorService singleThreadPool = Executors.newSingleThreadPool();

源码:

 

线程池常问的一些问题:

ExecutorService .execute和ExecutorService.submit方法有什么区别 executer提交任务但是不会返回结果,不会返回异常,submit 会返回结果和异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值