线程池相关知识点

参考路线:https://blog.csdn.net/pfnie/article/details/52757002

首先明确一点:
   线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

 Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool : 允 许 的 请 求 队 列 长 度 为
Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM;
2)CachedThreadPool 和 ScheduledThreadPool : 允 许 的 创 建 线 程 数 量 为
Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

先来看看execute能创建的4中线程池 通过工厂方法给我们提供的线程池

1.定长线程池 未设置队列长度
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

2.单线程池
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。
此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));

3.缓存线程池 未设置线程数量 最大线程数量为maxvalue 创建太多oom
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。
此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());

4.任务调度线程池 最大线程数量为maxvalue 创建太多oom
可以调度命令在一个给定的延迟后运行,或周期性地执行。

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());

接下来看看ThreadPoolExecutor

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

corePoolSize与maximumPoolSize 核心线程数和最大线程数 
由于ThreadPoolExecutor是根据core和max 设置的边界值自动调整池大小
当执行 execute(java.lang.Runnable) 方法提交新任务时:
1.。如果运行的线程少于corePoolSize,则创建新的线程来处理请求,其他辅助线程是空闲的
2.。如果二者设置的是相同的,则创建的线程池大小是固定的,如果运行的线程与core核心线程数相同,当新的请求过来的时候若workqueue任务阻塞队列未满,则将请求放入workqueue中,等待有空闲的线程从workqueue中取出任务并处理
3.。如果运行的线程多余core少于max ,则仅仅当workqueue任务阻塞队列满时才去创建新线程去处理请求

4.。如果运行的线程多于core并且等于max,若工作队列满了,则通过handle所指定的策略去处理新的请求

5.。如果将max设置为基本的无界值 如Integer.MAX_VALUE,则允许池适应任意数量的并发任务

任务处理的优先级为:
1.。核心线程数>阻塞队列>最大线程数  如果三者都满了 使用handle处理被拒绝的任务
2.。当线程池中的线程数大于core数的时候,多余的线程就会等待keepAliveTime长的时间 如果没有请求处理,就自行销毁。

 

 

corePoolSize
在创建线程池以后 默认情况下 线程池中并没有任何线程,而是等待任务来之后才会去创建线程去处理请求 创建线程池后默认线程为0,任务来了之后会创建一个线程去执行任务,当池中的数目达到core之后,就会把任务放到阻塞队列中
maximumpoolsize 
一表示最大的线程数量
workQueue 
线程池所使用的任务阻塞队列,改阻塞队列的长度决定了能够缓冲任务的最大数量,阻塞队列有三种选择

ArrayBlockingQueue;  有界队列      用的少

LinkedBlockingQueue;  无界队列   一般用此队列

SynchronousQueue;  特殊的一个队列 只有存在等待取出的线程时才能加入队列,可以说是容量为0 是无界队列

 keepAliveTime
表示线程没有任务执行时最多保持多久会终止
默认情况下只有当线程池中的线程数大于核心线程数时 keepaliveTime才会起作用
Timeunit时间单位参数 有7种取值  (天 小时 分钟 秒 毫秒 微秒 纳秒)

添加任务的处理流程:

当一个任务通过execute(runnable)方法欲添加到线程池时:
1.。如果当前线程池中的数量少于 core时,并且池处于running状态,那么创建并添加任务

2.。若当前=core 池处于running状态 并且队列没有满,那么任务被放入缓冲队列等待任务调度执行

3.。若大于core 队列满 小于最大线程数 那么新提交的任务会创建新的线程执行
4..若大于core  队列满 并且 线程池中的数量等于最大数量,新提交的数量会由handle来处理

5.。若大于core 多余线程空闲时间超过keepaliveTime时 会关闭这部分线程

工作线程数是不是设置的越大越好?
回答:肯定不是的
1)一来服务器CPU核数有限,同时并发的线程数是有限的,1核CPU设置10000个工作线程没有意义
2)线程切换是有开销的,如果线程切换过于频繁,反而会使性能降低

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值