线程池有哪些问题
3.1 队列过大
Executors.newFixedThreadPool,它可以创建固定线程数量的线程池,任务队列使用的是LinkedBlockingQueue,默认最大容量是Integer.MAX_VALUE。
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
如果向newFixedThreadPool线程池中提交的任务太多,可能会导致LinkedBlockingQueue非常大,从而出现OOM问题。
3.2 线程太多
Executors.newCachedThreadPool,它可以创建可缓冲的线程池,最大线程数量是Integer.MAX_VALUE,任务队列使用的是SynchronousQueue。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0,
Integer.MAX_VALUE,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
如果向newCachedThreadPool线程池中提交的任务太多,可能会导致创建大量的线程,也会出现OOM问题。
3.3 数据丢失 本文重点
如果线程池在执行过程中,服务突然被重启了,可能会导致线程池中的数据丢失。
上面的OOM问题,我们在日常开发中,可以通过自定义线程池的方式解决。
比如创建这样的线程池:
new ThreadPoolExecutor(8,
10,
30L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(300),
threadFactory);
自定义了一个最大线程数量和任务队列都在可控范围内线程池。
这样做基本上不会出现OOM问题。
但线程池的数据丢失问题,光靠自身的功能很难解决。
3.3.1 如何保证数据不丢失?
线程池中的数据,是保存到内存中的,一旦遇到服务器重启了,数据就会丢失。
- case 主流程依赖子流程 这种大部分业务场景要考虑任务丢失
- case 主流程不依赖子流程 这种大部分业务场景不需要考虑任务丢失
-
那么,如何保证数据不丢失呢?
-
答:需要
提前做持久化。
我们优化的系统流程如下:
方案一
方案二
