Java线程池创建
0.回顾
之前一篇讲的比较乱,主要整理自别人的。这次自己记一下想要说的问题。
想要理解的就是,常用线程池,手动创建线程池,关于核心线程和工作线程。
以及补充一下阻塞队列,还有拒绝策略。
1.常用线程池
newCachedThreadPool
:Cached,可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。newFixedThreadPool
:Fixed,定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。newSceduledThreadPool
:Scheduled,定长线程池,支持定时及周期性任务执行。newSingleThreadExecutor
:Single,单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
2.详细参数
其实主要就是看一下他们的创建方式。
2.0 手动创建线程池
首先回忆一下手动创建线程池的重要参数:
1 | /** |
- 核心线程数
- 最大线程数
- 存活时间,时间单位
- 阻塞队列
- 线程工厂(可忽略):用来设置线程名字的,默认为
pool-线程池数-thread-线程数
- 拒绝策略(可忽略):默认拒绝策略为
AbortPolicy
,即 丢弃任务并抛出异常RejectedExecutionException
2.0.1 拒绝策略
拒绝策略有四种,简单提一下:
AbortPolicy
:丢弃任务,抛出异常DiscardPolicy
:丢弃任务,静默丢弃DiscardOledestPolicy
:丢弃队列中最老的未处理请求,然后再次尝试提交新任务。CallerRunsPolicy
:在调用者线程中,运行当前被丢弃的任务。
也就是说,两个丢弃当前任务(不管新任务);
一个丢弃队列中最老任务(新任务重要老任务可以不管);
一个让别人执行任务(调用当前线程的线程);
2.0.2 阻塞队列
阻塞队列中的有界无界就是说最大存储容量,但是是理想的。无界一般都是指 Integer.MAX_VALUE
,int的最大值个数。有界就是自己来指定容量。
1.SynchronousQueue
SynchronousQueue
是一个没有数据缓冲的同步队列,不存储元素。
每一个put操作必须等待一个take操作,否则不能继续添加元素。
常用于生产者消费者问题,负责把生产者线程处理的数据直接传递给消费者线程。
2. LinkedBlockingQueue
LinkedBlockingQueue
,基于链表(linked nodes)的可选界(optionally-bounded)的双向阻塞队列,线程安全。
可以对first、last元素进行操作,两端都可以入队出队。
默认容量为 Integer.MAX_VALUE
,无界队列。
3.DelayedWorkQueue
DelayedWorkQueue
,一个定制的专门用于存储Runnable任务的队列。
优先级队列,基于堆结构的等待队列,最小堆。
最近要到达时间的节点放在堆顶,每个节点都会附带到期时间,依次作为堆调整的依据。
2.1 Cached
Cached,缓存的;
1 | public static ExecutorService newCachedThreadPool() { |
分析一下其参数:
- 核心线程:0个,也就是说
- 最大线程数:Integer的最大值,反正也是很多了
- 存活时间、单位:60秒
- 阻塞队列:
SynchronousQueue
,同步队列,无容量
这样的话,其关键在于核心线程0个和这个同步队列。
来一个线程就创建一个非核心线程,因为队列中不存储任何元素。
用完1分钟后销毁,所以说是Cached缓存一下。
2.2 Fixed
Fixed,固定的(固定数量的)
1 | public static ExecutorService newFixedThreadPool(int nThreads) { |
参数:
- 核心线程:传入的n
- 最大线程:传入的n
- 存活时间、单位:0毫秒
- 阻塞队列:
LindedBlockingQueue
,链表双向阻塞队列
这个的关键是在 核心线程数==最大线程数
,所有的线程都是核心线程,不会销毁。
然后不考虑Integer最大值的话,是无界的,也就是说使用核心线程去处理所有任务。
其中的线程数是固定的不会销毁的,所以说是Fixed。
2.3 Scheduled
Scheduled,预定的;
1 | public ScheduledThreadPoolExecutor(int corePoolSize) { |
参数:
- 核心线程:传入的c
- 最大线程:Integer最大值
- 存活时间、单位:0纳秒
- 阻塞队列:
DelayedWorkQueue
,延迟队列,小根堆。
其关键在于这个队列,优先级队列小根堆。
这是一个可以定时、周期性执行的线程池,它继承FutureTask
并实现了接口RunnableScheduledFuture
。
里面有个参数time,指的是执行时间。有个函数setNextRunTime()
,可以设置下次执行时间。
小根堆的优先级就是根据时间来排序的。
2.4 Single
Single,单例
1 | public static ExecutorService newSingleThreadExecutor() { |
参数:
- 核心线程:1
- 最大线程:1
- 存活时间、单位:0毫秒
- 阻塞队列:
LinkedBlockingQueue
其关键在于,核心线程和最大线程都是1。
而且是无界队列,也就是说只有一个线程存活并执行。其他任务都排队。
所以说是Single。
3. 补充
有一点比较重要的,之前一直理解错了。。。
也就是说线程池中的核心线程,和非核心线程,并没有什么区别,他们都是普通线程,并没有什么参数来区分他们。
在回收线程非核心线程的时候,看谁闲着并且超过存活时间了,就去回收它。
啊,就这样吧。