ArrayBlockingQueue: (有界队列) 是一个数组实现的有界阻塞队列,按FIFO排序量
LinkedBlockingQueue : 是一个基于链表实现的阻塞队列,按FIFO排序任务,可以设置容量,不设置使用Integer.Max_VALUE (不设置就是无界队列)newFixThreadPool,newSingleThreadExecutor使用此队列
(吞吐量高于ArrayBlockingQueue)
DelayQueue : (延迟队列)是一个任务定时周期的延迟执行的队列。根据插入到队列的先后。newScheduledTreadPool线程池使用这个队列。
PriorityBlockingQueue : (优先级队列) 是具有优先级的无界队列;
SynchronousQueue : (同步队列) 一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程的调用移除操作,否则插入操作一直处于阻塞状态。吞吐量通常高于LinkedBlockingQuene newCachedThreadPool 线程池使用此队列。
newFixedThreadPool(固定数目的线程池)
newCachedThreadPool(可缓存线程的线程池)
newSingleThreadExecutor(单线程的线程池)
newScheduledThreadPool(定时及周期执行的线程池)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
使用场景:
fixedThreadPool核心线程池等于最大线程池,当前的线程数能够比较稳定保证一个数。能够避免频繁回收线程和创建线程。故适用于处理cpu密集型的任务,确保cpu在长期被工作线程使用的情况下,尽可能少的分配线程,即适用长期的任务。
此方法的弊端是:
到了线程池最大容量后,如果有任务完成让出占用线程,那么此线程就会一直处于等待状态,而不会消亡,直到下一个任务再次占用该线程。这就可能会使用无界队列来存放排队任务,当大量任务超过线程池最大容量需要处理时,队列无线增大,使服务器资源迅速耗尽。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
使用场景:
newCacehedThreadPool 的最大特点就是,线程数量不固定。只要有空闲线程空闲时间超过keepAliveTime,就会被回收。有新的任务,查看是否有线程处于空闲状态,如果不是就直接创建新的任务。故适用用于并发不固定的短期小任务。
此方法的弊端是:
线程池没有最大线程数量限制,如果大量的任务同时提交,可能导致创线程过多会而导致资源耗尽。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
使用场景:
newSingleThreadExecutor 适用串行化任务,一个任务接着一个一个任务的执行。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
使用:
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(2);
scheduled.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
loge("time:");
}
}, 0, 40, TimeUnit.MILLISECONDS);
//0表示首次执行任务的延迟时间,40表示每次执行任务的间隔时间
//TimeUnit.MILLISECONDS执行的时间间隔数值单位
使用场景:
ScheduledThreadPoolExecutor 适用于定时操作一些任务
虽然Executors为我们提供了构造线程池的便捷方法,对于服务器程序我们应该杜绝使用这些便捷方法,而是直接使用线程池ThreadPoolExecutor的构造方法,避免无界队列可能导致的OOM以及线程个数限制不当导致的线程数耗尽等问题。ExecutorCompletionService提供了等待所有任务执行结束的有效方式,如果要设置等待的超时时间,则可以通过CountDownLatch完成。
线程拒绝策略:
是系统超负荷运行的最后补救措施,,阻塞队列满了,最大线程池也满了,jdk提供丢弃策略有如下四种:
(1)ThreadPoolExecutor.AbortPolicy:抛出RejectedExecutionException异常,丢弃任务,阻止系统正常工作。 (Executors类创建线程池的默认丢弃策略)
(2)ThreadPoolExecutor.DiscardPolicy:偷偷的丢弃任务,但是不抛出异常。
(3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃最老的任务(即队首马上要执行的任务),然后重新尝试执行任务(重复此过程)
(4)ThreadPoolExecutor.CallerRunsPolicy:只要线程池未关闭,直接去调用线程池的线程中处理该任务,可能引起性能的急剧下降。
(1)execute没有返回值;而submit有返回值,方便返回执行结果。
(2)submit方便进行Exception处理,由于返回参数是future,如果执行期间抛出了异常,可以使用future.get()进行捕获。
合理的选择线程池大小:
CPU核数 * CPU核数 *(1+等待时间 / 计算时间)
线程池的几种状态:
Running
会接受新任务,处理阻塞队列的任务
调用 Shutdown() 切换为Shutdown 状态
调用 shutdownNow() 切换到STOP状态
Shutdown
不接受新任务,会处理阻塞队列的任务
阻塞队列的任务为空,线程池中的线程执行的任务也为空,变为TIDYING
Stop
不接受新任务,不会处理阻塞队列的任务,而且中断正在执行的任务。
线程池中正在执行的任务为空,则变为TIDYING
TIDYING
表明所有任务执行完毕,记录任务的数量为0
Terminated() 执行完毕,进入TERMINATED状态
TERMINATED
线程池彻底终止