Java线程池ThreadPoolExector
分析过很多遍,面试的常考点,每次面试又得重新看,自己写到面试整理里了,这次发出来
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
用给定的初始参数创建新的 ThreadPoolExecutor。
参数:
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序创建新线程时使用的工厂。
handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
抛出:
IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。
NullPointerException - 如果 workQueue、threadFactory 或 handler 为 null。
在创建线程池的时候,第一次使用的时候线程池中并没有线程,当有任务到达的时候才会开始创建线程来执行任务,直到池中的线程数到达corePoolSize之后,会将之后的任务添加到任务队列中进行缓存,这是为了防止任务过多不能及时响应。然后尝试创建新的线程来执行任务。
例如:new ThreadPoolExecutor(5,20,30L,TimeUnit.SECONDS,new LinkedBlockingQueue(10));
指定的核心线程数为5,线程池中最多可以容纳的线程为20个,当超过核心线程数之外的线程陷入空闲状态超过30秒(30秒还没等到任务)时这些线程就会被终止,但是核心线程之内的线程不论空闲多久都是不会被回收的,会一直保存在线程池中,下次在执行的任务的时候就可以直接拿来用。注意这里指定了阻塞队列的大小为10,队列中最多缓存10个任务,队列满了之后就会创建新的线程来执行任务,直到到达最大的线程数,如果任务还是执行不完就会抛出拒绝执行的异常。如果是在web请求中,任务较多可以不指定阻塞队列的大小这样就是无界队列,默认大小为Integer.MAX_VALUE,只要阻塞队列不满就不会去创建新的线程去执行任务,线程池中最多只有核心线程数个线程,设定的最大线程数就不会起作用。
假如现在来了21个任务,就会先创建5个线程来执行任务,然后先将10个任务添加到阻塞队列中,等到阻塞队列满了之后,然后开始创建10个新的线程来执队列中的10个任务,然后将剩下的5个任务再放到阻塞队列中,等其他任务执行完毕之后,再执行。对于非核心线程执行完任务知乎它的生命就结束了,但是还有5个核心线程会一直保存在线程池中,当下次再有任务到达的时候,可以直接从线程中取出来用。
package test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args){
BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<Runnable>(3);
ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,15, 30L,TimeUnit.SECONDS,workQueue);
for (int i=1;i<=20;i++){
tpe.execute(new MyTask("Thread-"+i));
}
/*
假如现在共有20个任务
先创建5个核心线程执行任务 (在执行的任务:1,2,3,4,5,线程数:5)
然后从剩下的15个任务中
拿3个任务(6,7,8)放到工作队列中,队满
开始创建3个线程执行队列中的任务 (在执行的任务:1,2,3,4,5,6,7,8,线程数:8)
再拿3个任务(9,10,11)放到队列中,队满
再创建3个线程执行队列中的任务 (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,线程数:11)
再拿3个任务(12,13,14)放到队列中,队满
再创建3个线程执行队列中的任务 (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,12,13,14,线程数:14)
再拿3个任务(15,16,17)放到队列中,队满
再创建1个线程执行队列中的任务 (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 线程数:15)
再放一个任务(18)到队列中,队满 (队列中:16,17,18)
线程数15个已达最大值,拒绝执行(19,20)
*/
}
}
class MyTask implements Runnable{
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+" is running........");
}
}
运行结果:
Thread-1 is running........
Thread-6 is running........
Thread-7 is running........
Thread-8 is running........
Thread-2 is running........
Thread-3 is running........
Thread-9 is running........
Thread-4 is running........
Thread-10 is running........
Thread-5 is running........
Thread-15 is running........
Thread-11 is running........
Thread-12 is running........
Thread-13 is running........
Thread-16 is running........
Thread-14 is running........
Thread-17 is running........
Thread-18 is running........
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task test.MyTask@355da254 rejected from java.util.concurrent.ThreadPoolExecutor@4dc63996[Running, pool size = 15, active threads = 0, queued tasks = 0, completed tasks = 18]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at test.ThreadPoolTest.main(ThreadPoolTest.java:16)