在工作中,一般需要我们自定义线程池,熟悉自定义线程池的创建。下面通过newSingleThreadExecutor的源码来查看如何自定义线程池。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
7大参数:
1、corePoolSize:核心线程数,保证线程池最少有多少线程,并且不受keepAliveTime的影响。
2、maximumPoolSize:最大线程数大小,当阻塞队列满了,就开启最大的线程池,并且受keepAliveTime的影响。
3、keepAliveTime:保持存活的时间,例如:设置存活的时间为三秒,当可执行的线程少于等于核心线程数并且3秒也没有新线程进来。就会关闭新开的线程处理。
4、TimeUnit:keepAliveTime的时间单位。
5、BlockingQueue:阻塞队列,让新来的线程等待,要输入一个队列的大小。
6、ThreadFactory:线程工厂,一般不用变。
7、拒绝策略:当线程达到最大线程数并且阻塞队列也满后,通过所选的拒绝策略来处理新来的线程。
拒绝策略:
下面是测试:
public static void main(String[] args) {
//创建线程池后,通过线程池来创建线程
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
try {
for (int i = 0; i < 6; i++) {
executor.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}finally {
executor.shutdown();
}
}
上面的核心线程数是2,并且阻塞队列是4,for循环执行6个线程,同时只会有两个线程处理。
运行结果:
当我for循环7次的时候,就会开启最大线程数。有其他线程来执行。
运行结果:
当超过阻塞队列数与最大线程数的和时,就会触发拒绝策略。
线程池的4大拒绝策略
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务,抛出异常
rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务,不抛出异常【如
//果允许任务丢失这是最好的】
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务
//删,之后再尝试加入队列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么
//主线程会自己去执行该任务,回退
如何获取电脑的最大线程数:
Runtime.getRuntime().availableProcessors()