Java线程池(ThreadPoolFactory)构造参数总结
来源:互联网 发布:德国表现主义电影知乎 编辑:程序博客网 时间:2024/05/16 02:26
今天看到关于线程池的一篇帖子,是关于面试时问到ThreadPoolFactory构造器时的一些问题,之前博主也学习过一些关于ThreadPoolFactory构造器的问题,但是一直没有总结过,既然今天有时间,那么就总结一下,避免有些同学走弯路(有些工作多年的老鸟也不一定能准确的说明coreSize,MaxSize,workQueueSize的关系),话不多说上干货。
下面来直接看ThreadPoolFactory最详细的构造器结构
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
从上面的代码块可以看出来在初始化时,对构造参数做了大小比较,一旦下面比较有一个为真就会抛出异常
corePoolSize<0maximumPoolSize<=0 maximumPoolSize<corePoolSizekeepAliveTime<0
从构造参数的入口可以看出主要的几个参数一共有如下几个
int corePoolSize
int maximumPoolSize
long keepAliveTime
TimeUnit unit
BlockingQueue workQueue
ThreadFactory threadFactory
RejectedExecutionHandler handler
而一般最让人迷糊的3个参数就是corePoolSize,maxmumPoolSize,workQueueSize
下面就针对这几个参数做下总结:
当线程池初始化时,PoolSize为0,当有任务向线程中提交时,线程池开始创建线程,用来执行业务。
一、corePoolSize、maxmumPoolSize、workQueueSize参数关系总结
JobCount代表向线程池中添加的任务数
1.JobCount <=corePoolSize<maxmumPoolSize<workQueueSize
(当JobCount小于等于corePoolSize时,workQueueSize与maxmumPoolSize无效,线程池会创建与JobCount个数一致的线程来执行任务)
2.corePoolSize <JobCount <=workQueueSize <maxmumPoolSize
(当JobCount大于corePoolSize并且小于等于workQueueSize时maxmumPoolSize无效,超出corePoolSize的任务,会在阻塞对列中排队,当corePoolSize中有线程闲置的时候,从workQueue中取出执行)
3.corePoolSize<workQueueSize<JobCount<maxmumPoolSize
(当JobCount大于corePoolSize时并且workQueue中也放满,但JobCount小于maxmumPoolSize时,那么线程池会创建线程来处理超出workQueueSize部分的任务)
4.corePoolSize<workQueueSize+maxmumPoolSize<JobCount
(当JobCount大于corePoolSize并且大于workQueueSize和maxmumPoolSize之和。那么线程池将会调用handler.rejectedExecution方法)
二、RejectedExecutionHandler参数总结
上面说了corePoolSize,maxmumPoolSize,workQueueSize 3个参数的用法了,那么接下来说一下RejectedExecutionHandler这个参数的意思。
从字面上理解为拒绝处理者,可以理解为当任务数大于maxmumPoolSize后的一个回调方法,RejectedExecutionHandler本身是一个接口,jdk本身对他有4个实现类
CallerRunsPolicy //线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度
AbortPolicy(如不指定handler则默认这个) //处理程序遭到拒绝将抛出运行时RejectedExecutionException;
DiscardPolicy //不能执行的任务将被删除
DiscardOldestPolicy //如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
三、KeepAliveTime、TimeUnit参数总结
TimeUnit参数很好理解,是一个用来当做单位的枚举。主要还是说说keepAliveTime这个参数,网上很多对这个参数都是几句话带过,说是用来控制线程回收时间的参数,确实他的作用就是这样,但是看下面例子
public class Test { public static void main(String[] args) { BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 5, 5, TimeUnit.SECONDS, queue); System.out.println("pool初始化时PoolSize大小:"+poolExecutor.getPoolSize()); System.out.println("pool初始化时active大小:"+poolExecutor.getActiveCount()); poolExecutor.execute(new Test().new Task("1")); poolExecutor.execute(new Test().new Task("2")); poolExecutor.execute(new Test().new Task("3")); poolExecutor.execute(new Test().new Task("4")); try { Thread.sleep(8000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("pool现在PoolSize大小:"+poolExecutor.getPoolSize()); System.out.println("pool现在active大小:"+poolExecutor.getActiveCount()); // poolExecutor.shutdown(); } class Task implements Runnable { String name; public Task(String name) { this.name = name; } @Override public void run() { int i=0; while (true) { i++; if (name.equals("4")) { if (i==5) { break; } } if (name.equals("2")) { if (i==2) { break; } } System.out.println(name); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }}
例子看上去不是太明白,但是keepAliveTime本身就不是很容易触发
1.keepAliveTime和maximumPoolSize及BlockingQueue的类型均有关系。如果BlockingQueue是无界的,那么永远不会触发maximumPoolSize,自然keepAliveTime也就没有了意义。
2.反之,如果核心数较小,有界BlockingQueue数值又较小,同时keepAliveTime又设的很小,如果任务频繁,那么系统就会频繁的申请回收线程。
上面的例子总结起来就是
1.假设corePoolSize=1,QueueSize=1,MaxmumPoolSize=5
2.当初始化线程池的时候CorePoolSize为0,假设这个时候来了4个任务为t1、t2、t3、t4
3.那么线程池会创建一个线程用来执行t1
4.接下来发现coreSize不足,那么将t2放到Queue中
5.又发现QueuePool的大小不够了,判断MaxSize大小没有超出,那么接下来申请线程执行t3和t4
6.,执行了一会发现t4执行完毕了,(PS:注意了)这个时候不管keepaliveTime不管设置的多小,也不会回收的,因为QueuPool中还有一个t2没有执行,那么现在就会拿刚才用来执行t4的线程执行t2,执行的时候发现t2执行的很快,那么现在线程池的状态就是一共有3个线程,两个属于active的,那么这个时候就靠keepAliveTime参数判断回收时间了。
可以将TimeUnit的单位修改为NANOSECONDS比较两次的输出,就会明白了
- Java线程池(ThreadPoolFactory)构造参数总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- Java线程池总结
- JAVA线程池总结
- java线程池参数含义
- 线程池中ThreadPoolExecutor构造器参数介绍
- java中的进程,线程,线程池总结
- java中的进程,线程,线程池总结
- Java线程池总结笔记
- JAVA线程池机制总结
- 20.Redis Cluster
- Codeforces Round #430 (Div. 2) A. Kirill And The Game
- 交互设计新手路要怎么走
- action和action之间传数据
- SQOOP from Oracle Connection reset error
- Java线程池(ThreadPoolFactory)构造参数总结
- 基于 Excel 参数化你的 Selenium2 测试代码
- synchronized同步代码块
- Codeforces-809C Find a car(分治)
- mac 下终端访问文件出现“Permission Denied”解决方案
- [LintCode]96.链表划分
- POJ-1742:Coins(多重背包二进制求法)
- Eclipse上Maven环境配置使用
- AESTool