1、函数介绍
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue)
ThreadPoolExecutor:
corePoolSize: 核心线程数,线程池维护线程的最少数量,即建议线程数
maximumPoolSize:线程池维护线程的最大数量(线程池里最大有corePoolSize个线程可运行)
keepAliveTime: 线程池维护线程所允许的空闲时间(当一个线程不工作时候,过keepAliveTime长时间将停止该线程)
unit: 线程池维护线程所允许的空闲时间的单位(keepAliveTime的单位)
workQueue: 线程池所使用的缓冲队列(存放需要被线程池执行的线程队列)
handler: 线程池对拒绝任务的处理策略(添加任务失败后处理方式:
1、AbortPolicy: 直接抛出一个RejectedExecutionException异常
2、DiscardPolicy: 什么也不做,任务自然被直接丢掉
3、DiscardOldestPolicy:如果线程池没有被shutdown,则会从BlockingQueue里取出一个任务,然后执行execute方法
4、CallerRunsPolicy: 如果线程池没有被shutdown,则会直接调用任务的run()方法,不过没有开启一个新的线程或交个线程池调度,而是直接使用生产者的当前线程来运行)
2、运行机制
线程池运行机制:
1、当调用execute()方法添加一个任务时候,线程池做以下判断:
a、如果正在运行的线程数 < corePoolSize,那就马上创建线程并运行这个任务,而不会进行排队。
b、如果正在运行的线程数 >= corePoolSize,那就把这个任务放入队列。
c、如果队列满了,并且正在运行的线程数 < maximumPoolSize,那么还是要创建线程并运行这个任务。
d、如果队列满了,并且正在运行的线程数 >= maximumPoolSize,那么线程池就会调用handler里方法。(采用LinkedBlockingDeque就不会出现队列满情况)
2、当一个线程完成任务时,它会从队列里取下一个任务来执行。
3、当一个线程执行完后,超过keepAliveTime时,线程池会判断,如果当前运行线程数 > corePoolSize,就会把这个线程停掉,到最后保持corePoolSize的大小。
3、Demo
情况1:
采用 LinkedBlockingDeque<Runnable>队列 队列大小没有限制不会出现 机制1中d的情况。
public class demo { private static int corepoolsize = 2; private static int maxpoolsize = 5; private static int keepalivetime = 1; public static void main(String[] args) { LinkedBlockingDeque<Runnable> queue = new LinkedBlockingDeque<Runnable>(); ThreadPoolExecutor threadpool = new ThreadPoolExecutor( corepoolsize, maxpoolsize, keepalivetime, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() ); for(int i=0;i<10;i++){ threadpool.execute(new ThreadPoolTask(String.valueOf(i))); System.out.println("当前队列大小 "+queue.size()); } threadpool.shutdown(); } } class ThreadPoolTask implements Runnable{ private String thName = null; public ThreadPoolTask(String name) { this.thName = name; } public void run() { System.out.println("I am "+this.thName+" start"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I am "+this.thName+" end"); } }
输出结果:
I am 0 start 当前队列大小 0 当前队列大小 0 I am 1 start 当前队列大小 1 当前队列大小 2 当前队列大小 3 当前队列大小 4 当前队列大小 5 当前队列大小 6 当前队列大小 7 当前队列大小 8 I am 0 end I am 2 start I am 1 end I am 3 start I am 3 end I am 2 end I am 4 start I am 5 start I am 5 end I am 4 end I am 6 start I am 7 start I am 7 end I am 8 start I am 6 end I am 9 start I am 8 end I am 9 end
情况2:
采用 ArrayBlockingQueue<Runnable>(3) 设置队列大小为3 corepoolsize = 2 maxpoolsize = 5
此时线程池的总容量 = 队列大小 + maxpoolsize,为8
当创建10个线程时,但只能同时让8个线程运行,插入第九个时就会调用handler方法,这里设置的是AbortPolicy
注意:这里每个线程里我都sleep(1000),保证了在创建第九个线程的时候,前8个线程都在运行状态,线程池是满的,所以创建时会抛出异常。
如果取消每个线程里sleep,之前线程执行完后就会被线程池回收空间,线程池处于不满的状态,就可以继续创建线程。
public class demo { private static int corepoolsize = 2; private static int maxpoolsize = 5; private static int keepalivetime = 1; private static int queuesize = 3; public static void main(String[] args) { ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(queuesize); ThreadPoolExecutor threadpool = new ThreadPoolExecutor( corepoolsize, maxpoolsize, keepalivetime, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() ); for(int i=1;i<=10;i++){ threadpool.execute(new ThreadPoolTask(String.valueOf(i))); System.out.println("当前队列大小 "+queue.size()); } threadpool.shutdown(); } } class ThreadPoolTask implements Runnable{ private String thName = null; public ThreadPoolTask(String name) { this.thName = name; } public void run() { System.out.println("I am "+this.thName+" start"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I am "+this.thName+" end"); } }
输出结果:
当前队列大小 0 当前队列大小 0 当前队列大小 1 当前队列大小 2 I am 2 start 当前队列大小 3 I am 1 start I am 6 start 当前队列大小 3 当前队列大小 3 I am 7 start 当前队列大小 3 I am 8 start Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.fedomn.demo.ThreadPoolTask@6a3522b5 rejected from java.util.concurrent.ThreadPoolExecutor@67291479[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372) at com.fedomn.demo.demo.main(demo.java:25) I am 2 end I am 3 start I am 7 end I am 4 start I am 6 end I am 5 start I am 1 end I am 8 end I am 3 end I am 5 end I am 4 end
4、总结
总结:
1、线程池 可以 处在运行状态的线程数 = maximumPoolSize
2、线程池可以承受的最大线程数(容量) = maximumPoolSize + 线程队列大小
3、当线程池满时 添加线程会有三种方式add抛异常 offer返回Boolean值 put直到添加成功为止 正好对应handle的处理方法 可以自己到API寻找