使用线程池的目的:
-
线程是稀缺资源,不能频繁的创建。
-
解耦作用;线程的创建于执行完全分开,方便维护。
-
应当将其放入一个池子中,可以给其他任务进行复用。
创建线程池的方式:
在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下三种:
-
Executors.newCachedThreadPool()
:无限线程池。 -
Executors.newFixedThreadPool(nThreads)
:创建固定大小的线程池。 -
Executors.newSingleThreadExecutor()
:创建单个线程的线程池。
但是在阿里巴巴开发规约中对线程池的创建有以下几个强制要求:
可以看到规约是不允许使用Executors直接创建线程池的,而要通过ThreadPoolExecutor的方式创建
1 public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<Runnable>()); 5 }
我们看到这三种方式的源码也是通过ThreadPoolExecutor的方式来创建的,接下来我们看一下ThreadPoolExecutor的API
1 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
这几个核心参数的作用:
-
corePoolSize
为线程池的基本大小。 -
maximumPoolSize
为线程池最大线程大小。 -
keepAliveTime
和unit
则是线程空闲后的存活时间。 -
workQueue
用于存放任务的阻塞队列。 -
handler
当队列和最大线程池都满了之后的饱和策略。
线程池大小创建的原则:
-
IO 密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如 CPU 个数 * 2
-
CPU 密集型任务(大量复杂的运算)应当分配较少的线程,比如 CPU 个数相当的大小。
通过SpringBoot管理线程池:
1 @Configuration 2 public class TreadPoolConfig { 3 4 5 /** 6 * 消费队列线程 7 * @return 8 */ 9 @Bean(value = "consumerQueueThreadPool") 10 public ExecutorService buildConsumerQueueThreadPool(){ 11 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() 12 .setNameFormat("consumer-queue-thread-%d").build(); 13 14 ExecutorService pool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, 15 new ArrayBlockingQueue<Runnable>(5),namedThreadFactory,new ThreadPoolExecutor.AbortPolicy()); 16 17 return pool ; 18 } 19 20 21 22 }
使用:
1 @Resource(name = "consumerQueueThreadPool") 2 private ExecutorService consumerQueueThreadPool; 3 4 5 @Override 6 public void execute() { 7 8 //消费队列 9 for (int i = 0; i < 5; i++) { 10 consumerQueueThreadPool.execute(new ConsumerQueueThread()); 11 } 12 13 }
其实也挺简单,就是创建了一个线程池的 bean,在使用时直接从 Spring 中取出即可。