线程池(一)
线程池重要参数
1.构造方法参数讲解
参数名 | 作用 |
corePoolSize | 队列未满时,线程最大并发数;核心线程池大小如:80 |
maximumPoolSize | 队列满后线程能够到达的最大并发数;最大线程池大小如:100 |
keepAliveTime |
线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间 大于80剩余线程存活的时间 |
TimeUnit | keepAliveTime时间单位 大于80剩余线程存活的时间 |
workQueue |
阻塞任务队列 :大于80之后进入该queue 如corePoolSize=5 实际有10个线程,超出的5个将会存放到待队列里 |
threadFactory | 新建线程工厂 |
RejectedExecutionHandler |
当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理; 如maxmumPoolSize=5,workQueue的size=2,实际最大线程为10>7超出的3个线程将会提交给RejectedExecutionHandler |
2.拒绝策略代码演示:
public class RejectedExecutionHandlerAction implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { executor.allowCoreThreadTimeOut(true); System.out.println("aaa"+ executor.getActiveCount()); } } public void test() throws InterruptedException { //队列不限定长度 无论实际有多少个线程都不会触发 RejectedExecutionHandler LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque(); RejectedExecutionHandlerAction action = new RejectedExecutionHandlerAction(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 5, TimeUnit.SECONDS, linkedBlockingDeque, action ); for (int i = 0; i < 10; i++) { threadPoolExecutor.execute(new Runnable() { @Override public void run() { System.out.println(" 线程名称:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入printA"); } }); } System.out.println(linkedBlockingDeque.size()); Thread.sleep(20000); System.out.println(linkedBlockingDeque.size()); }
运行结果:
指定队列长度,超出线程触发RejectedExecutionHandler
LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque(2);
-
corePoolSize,maximumPoolSize,workQueue之间关系。
-
当线程池中线程数小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
-
当线程池中线程数达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 。
-
当workQueue已满,且maximumPoolSize > corePoolSize时,新提交任务会创建新线程执行任务。
-
当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理。
-
当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收这些线程。
-
当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收。
-
3.线程管理机制图示:
Executors提供的线程池配置方案
1、newFixedThreadPool
构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理
ExecutorService executorService = Executors.newFixedThreadPool(10);
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
2、newCachedThreadPool
构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁
ExecutorService executorService2 = Executors.newCachedThreadPool(); public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
非核心线程Worker未执行完当前Task,创建新的Worker接收新的Task
3、newSingleThreadPool
构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行
4、newScheduledThreadPool
构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
- return new ScheduledThreadPoolExecutor(corePoolSize);
- }
- public static ScheduledExecutorService newScheduledThreadPool(
- int corePoolSize, ThreadFactory threadFactory) {
- return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
- }
- public ScheduledThreadPoolExecutor(int corePoolSize,
- ThreadFactory threadFactory) {
- super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
- new DelayedWorkQueue(), threadFactory);
- }
线程池中execute和submit的区别
submit有返回值execute没有返回值,submit底层还是 调用的execute方法
submit方法:
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
实现原理:
类图
拒绝策略
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
- ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(默认策略)
- ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务(丢弃老任务,接收新任务)
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务