(一).线程池的详解与使用
@1) 核心:ThreadPoolExecutor类public ThreadPoolExecutor(int corePoolSize, //核心线程数
int maximumPoolSize, //线程允许创建的最大线程数
long keepAliveTime, //非核心线程闲置的超时时间
TimeUnit unit, //超时时间的单位
BlockingQueue<Runnable> workQueue, //任务队列-->阻塞队列
RejectedExecutionHandler handler) //饱和策略
@2)处理流程与原理:
提交任务之后,线程池先判断线程数是否达到核心线程数。如果未达到核心线程数,则创建核心线程处理任务;否则就执行下一步--->
接着线程池会判断任务队列是否满了。如果没满,则将任务添加到任务队列中;否则就执行下一步--->
接着因为任务队列满了,线程池就判断线程数是否达到了最大线程数。如果未达到了,则创建非核心线程来处理任务;否则就执行饱和策略,默认
抛出RejectedExecutionException异常。
@3)分批简介Executors框架中常用的四中线程池:
1)Executors.newFixedThreadPool(int nThreads):创建一个可重用的,具有固定线程数的线程池【核心线程不会被回收】。
源码:public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
解析:指定的参数nThreads:这意味着FixedThreadPool只有核心线程,并且数量是固定的,没有非核心线程。
keepAliveTime设置为0L:这意味着多余的线程会被立即终止。因此不会产生多余的线程。所以unit是无效参数。
LinkedBlockingQueue任务队列采用的是无界的阻塞队列:这意味着当执行的任务达到核心线程数时,则将任务添加到
LinkedBlockingQueue中存储起来,直到线程池中有空闲线程时,则从任务队列取任务。
2)Executors.newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程池,这些线程将会被缓存在线程池中。
源码: public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
解析:corePoolSize设置为0:这意味着CachedThreadPool没有核心线程。
maximumPoolSize设置为Integer.MAX_VALUE:这意味着非核心线程数是无界的。
keepAliveTime设置为60L:这意味着空闲线程等待新任务的最长时间为60秒。
SynchronousQueue任务队列采用的是不存储元素的阻塞队列:每个插入操作必须等待另一个线程的移除操作。同理...。
也就是说:如果60s后没有提交任务到任务队列中,则空闲线程将终止,因为SynchronousQueue是无界的,
所以如果提交的任务大于线程池中线程处理任务的速度就会不断地创建新线程。
总结:CachedThreadPool比较适合大量的需要立即处理并且耗时较少的任务。
3)Executors.newSingleThreadExecutor():创建一个只有单线程的线程池,相当于调用newFixedThreadPool(1)方法。
总结:SingleThreadExecutor能确保所有的任务在一个线程中按照顺序逐一执行。
4)Executors.newScheduledThreadPool(int corePoolSize):创建一个具有指定线程数的线程池,它可以在指定延迟后执行线程任务。
也就是说:是一个能够实现定时和周期性任务的线程池。
源码: public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,new DelayedWorkQueue());
}
解析:最终还是调用了ThreadPoolExecutor构造方法,采用DelayedWorkQueue延时获取元素的无界阻塞队列。
DelayedWorkQueue(创建元素时,可以指定元素到期的时间,只有在元素到期时才能买从队列中取走)
(二) volatile关键字的讲解(补充)
1). 一句话涉及多个线程对一个变量进行访问时,如果对这个变量进行volatile关键词修饰,那么当其它线程改变值时,所有线程都会感知到它的变化。
2). 使用volatile要具备两个条件:对变量的写操作不会依赖与当前值;该变量没有包含在具有其它变量的不变式中。
下篇为线程池与锁的小实例demo