我们来看一个简单的线程池。
首先创建一个Runnable接口的实现类(当然也可以是Callable接口,我们上面也说过两者的区别)
package com.study; import java.util.Date; public class MyRunnable implements Runnable{ private String command; public MyRunnable(String s){ this.command = s; } public void run() { System.out.println(Thread.currentThread().getName() + " Start. Time = "+new Date()); processCommand(); System.out.println(Thread.currentThread().getName() + " End. Time = "+new Date()); } private void processCommand(){ try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } } @Override public String toString() { return this.command; } }
编写测试程序,通过ThreadPoolExecutor构造函数自定义参数的方式来创建线程池。
package com.study; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorDemo { //核心线程数 private static final int CORE_POOL_SIZE = 5; //最大线程数 private static final int MAX_POOL_SIZE = 10; // private static final int QUEUE_CAPACITY = 100; //等待时间 private static final Long KEEP_ALIVE_TIME = 1L; public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,//等待时间单位为秒 new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY),//任务队列 new ThreadPoolExecutor.CallerRunsPolicy());//饱和策略 for (int i = 0;i<10;i++){ Runnable worker = new MyRunnable(""+i); executor.execute(worker); } executor.shutdown(); while (executor.isTerminated()){ System.out.println("Finished all threads"); } } }
可以看到以上代码我们指定了:
1、corePoolSize:核心线程数为5.
2、maximumPoolSize:最大线程数10
3、keepAliveTime:等待时间为1L;
4、unit:等待时间的单位为TimeUnit.SECONDS
5、workQueue:任务对流为ArrayBlockingQueue,并且容量为100;
6、handler:饱和策略为CallerRunsPolicy
输出:
pool-1-thread-3 Start. Time = Tue Oct 13 19:02:04 CST 2020 pool-1-thread-1 Start. Time = Tue Oct 13 19:02:04 CST 2020 pool-1-thread-5 Start. Time = Tue Oct 13 19:02:04 CST 2020 pool-1-thread-4 Start. Time = Tue Oct 13 19:02:04 CST 2020 pool-1-thread-2 Start. Time = Tue Oct 13 19:02:04 CST 2020 pool-1-thread-5 End. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-2 End. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-1 End. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-3 End. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-4 End. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-3 Start. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-4 Start. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-2 Start. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-5 Start. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-1 Start. Time = Tue Oct 13 19:02:09 CST 2020 pool-1-thread-2 End. Time = Tue Oct 13 19:02:14 CST 2020 pool-1-thread-3 End. Time = Tue Oct 13 19:02:14 CST 2020 pool-1-thread-5 End. Time = Tue Oct 13 19:02:14 CST 2020 pool-1-thread-1 End. Time = Tue Oct 13 19:02:14 CST 2020 pool-1-thread-4 End. Time = Tue Oct 13 19:02:14 CST 2020
ThreadPoolExecutor类分析
ThreadPoolExecutor类中提供了四个构造方法,我们来看最长的那个,其余三个都是在这个构造方法的基础上产生(其他几个构造方法说白点都是给定某些默认参数的构造方法,比如默认指定拒绝策略是什么)
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.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
【重要】
ThreadPoolExecutor构造函数重要参数分析:
3个重要的参数:
1、corePoolSize:核心线程数,定义了最小可以同时运行的线程数量。
2、maximumPoolSize:当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
3、workQueue:当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
其他参数:
1、keepAliveTime:当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime才会被回收销毁。
2、unit:keepAliveTime参数的时间单位。
3、threadFactory:executor创建新线程的时候会用到。
4、handler:饱和策略,关于饱和策略线面单独介绍一下。
ThreadPoolExecutor饱和策略: