1. Why(为什么要使用线程池)
- 创建和销毁线程需要消耗系统资源,线程池可以复用已创建的线程
- 控制并发的数量。并发数量不加控制,可能会导致系统资源耗尽,造成服务器崩溃(主要原因)
- 对线程做统一管理
2. What(线程池的原理)
参数说明
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime 线程存活时间
unit 时间单位,枚举类型(NANOSECONDS:微毫秒;MICROSECONDS:微秒;MILLISECONDS:毫秒;SECONDS:秒;MINUTES:分钟;HOURS:小时;DAYS:天;)
BlockingQueue<Runnable> workQueue 等待执行的任务对象
ThreadFactory threadFactory 线程工厂
RejectedExecutionHandler handler 拒绝策略
重点
- BlockingQueue
任务对象又分为4中类型
ArrayBlockingQueue 数组阻塞队列,底层数据结构是数组。
LinkedBlockingQueue 链式阻塞队列,底层数据结构是链表。
SynchronousQueue 同步队列,内部容量为0。每个put操作必须等待一个take操作,反之亦然。
BlockingQueue 延迟队列,该队列中的元素只有当其指定的延时时间到了,才能从队列中获取到该元素。
- ThreadFactory
创建线程的工厂,用于批量创建线程,统一在创建线程时候设置一些参数。如:是否是守护线程、线程优先级等。
- RejectedExecutionHandler
拒绝处理策略。当线程数大于最大执行线程数就会采用拒绝处理策略,有4中拒绝处理策略:
1. ThreadPoolExecutor.CallerRunsPolicy(); // 由调用线程处理该任务
2. ThreadPoolExecutor.AbortPolicy(); //默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常
3. ThreadPoolExecutor.DiscardPolicy(); //丢弃新来的任务,但不抛出异常
4. ThreadPoolExecutor.DiscardOldestPolicy(); //丢弃队列头部(最旧的)任务,然后重新执行程序
工作原理:
1. 线程池首先判断当前在运行的线程是否少于corePoolSiz(核心线程数)。如果是,则创建一个新的工作线程来执行任务;如果不是,进入2。
2. 判断BlockingQueue(工作队列)是否已经满了。如果还没满,将线程放入BlockingQueue;如果已满,进入3。
3. 判断当前运行的线程是否大于maximumPoolSize(最大线程数)。如果不是分配一个新的任务给空闲的线程执行;如果线程池满了,则交给RejectedExecutionHandler(饱和策略)来处理任务。
3. How(怎么用)
1. newCachedThreadPool
private static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<>());
}
特点:
1. newCachedThreadPool线程池中最大线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue阻塞队列;
2. newCachedThreadPool线程池在没有任务执行时,当线程空闲时间超过keepAliveTime,会自动释放线程资源。
2. newFixedThreadPool
public static ExecutorService newFixedThreadPool(int corePoolSize) {
return new ThreadPoolExecutor(corePoolSize, corePoolSize, 0L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。