5、线程池知识点整理
1)、线程池类型:
newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,
可灵活回收空闲线程,若无可回收,则新建线程;
newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,
超出的线程会在队列中等待;
newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行;
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用
唯一的工作线程来执行任务,保证所有任务按照
指定顺序(FIFO, LIFO, 优先级)执行。
newSingleThreadScheduledExecutor:只有一个线程,用来调度执行将来的任务。
2)、线程池示例参数:
new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,
TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
a)、第一个参数:corePoolSize,核心线程数量,
b)、第二个参数:int maximumPoolSize,线程池最大线程数
c)、第三个参数:long keepAliveTime,表示线程没有任务执行时最多保持多久时间会终止
d)、第四个参数:TimeUnit unit,参数keepAliveTime的时间单位,有7种取值
e)、第五个参数:workQueue,一个阻塞队列,通过execute方法提交的runnable对象
会存储在该队列中
其中阻塞队列分为以下几种:
(1)、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务
(2)、LinkedBlockingQueue:基于链表结构的阻塞队列,按FIFO排序任务,吞
吐量通常要高于ArrayBlockingQuene;是无界的,可以不指定队列的大小,但是
默认是Integer.MAX_VALU。
(3)、SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到
另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于(2);
(4)、priorityBlockingQueue:具有优先级的无界阻塞队列;
3)、线程池的饱和策略
当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,
线程池提供了4种策略:
a)、ThreadPoolExcutor.AbortPolicy()——直接抛出异常,默认操作;
b)、ThreadPoolExcutor.CallerRunsPolicy()——只用调用者所在线程来运行任务;
c)、ThreadPoolExcutor.DiscardOldersPolicy()——丢弃队列里最近的一个任务,
并执行当前任务;
d)、ThreadPoolExcutor.DiscardPolicy()——不处理,直接丢掉;
也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略。
4)、执行流程:
执行excute()方法之后
a)、判断线程池存在核心线程的数量与corePoolSize的大小,
若小于corePoolSize,则调用addWorker函数创建新线程;
否则执行b;
b)、判断等待队列是否已满,若未满,则加入队列中;否则执行c;
c)、判断线程池是否已满,若未满,则创建线程执行任务;否则执行d;
d)、按照饱和策略,处理任务
部分源码(核心在addWorker):
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
流程图(网上找的):