共计 2132 个字符,预计需要花费 6 分钟才能阅读完成。
欢送来到狗哥多线程系列连载。这篇简略聊聊线程池的阻塞队列。
线程池的内部结构
如图所示,线程池的内部结构次要由线程池管理器、工作线程、工作队列以及工作四局部组成。
线程池的阻塞队列
先上张图,表格左侧是线程池,右侧为它们对应的阻塞队列,你能够看到 5 种线程池对应了 3 种阻塞队列。
上面逐个说下它们的特点:
- LinkedBlockingQueue,底层是链表构造、采纳先进先出准则,默认容量是 Integer.MAX_VALUE,简直能够认为是无界队列(简直不可能达到这个数)。而 因为 FixedThreadPool 和 SingleThreadExecutor 的线程数是固定的,所以只能用容量无穷大的队列来存工作。
- SynchronousQueue,容量为 0,不做存储,只做转发。因为 CachedThreadPool 的最大线程数是 Integer.MAX_VALUE,有工作提交就转发给线程或者创立新线程来执行,并不需要队列存储工作。所以在自定义应用 SynchronousQueue 的线程池应该把最大线程数设置得尽量大,防止工作数大于最大线程数时,没方法把工作放到队列中也没有足够线程来执行工作的状况。
- DelayedWorkQueue,外部用的是堆数据结构,初始容量为 16,跟 hashmap 一样动静扩容,对工作延时长短进行排序。
为什么不主动创立线程池?
阿里巴巴 Java 规约也约定了,手动创立线程池,成果会更好。为什么呢?答复这个问题之前,先来看看五种线程池初始化的办法:
// FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0 L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue <
Runnable > ());
}
// SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0 L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue <
Runnable > ()));
}
首先是 FixedThreadPool 和 SingleThreadExecutor,它两的问题在于都是用默认容量的无界队列 LinkedBlockingQueue,当工作解决慢时,队列迅速积压工作并占用大量内存,产生 OOM(内存溢出)。所以在应用时咱们能够依据业务指定队列长度:
ExecutorService threadPool = new ThreadPoolExecutor(2, 5,
1 L, TimeUnit.SECONDS,
new LinkedBlockingQueue < > (3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
而后是 CachedThreadPool,也能够发现一个问题:它默认的最大线程是 Integer.MAX_VALUE,当工作贼多时,它就会一直创立线程,而线程执行比拟耗时来不及回收。最终也会造成 OOM,所以应该手动指定最大线程数。
// CachedThreadPool
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60 L, TimeUnit.SECONDS, new SynchronousQueue < Runnable > ());
}
最初是 ScheduledThreadPool 和 ScheduledThreadPoolExecutor,这两问题就更大了。首先最大线程数是 Integer.MAX_VALUE,而后阻塞队列是 DelayedWorkQueue,它也是无界队列,最终还是会造成 OOM。
// ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}
// ScheduledThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
小福利
如果看到这里,喜爱这篇文章的话,请帮点个难看。微信搜寻 一个优良的废人 ,关注后回复 电子书 送你 100+ 本编程电子书,不只 Java 哦,详情看下图。回复 1024送你一套残缺的 java 视频教程。
正文完