阿里巴巴的开发手册中推荐使用ThreadPoolExecutor
来创建线程池,而不是Executors
工具类
Executors
返回线程池对象的弊端如下:
-
FixedThreadPool
和SingleThreadExecutor
:使用的是无界的LinkedBlockingQueue
,任务队列最大长度为Integer.MAX_VALUE
,可能堆积大量的请求,从而导致 OOM。 -
CachedThreadPool
:使用的是同步队列SynchronousQueue
, 允许创建的线程数量为Integer.MAX_VALUE
,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致 OOM。 -
ScheduledThreadPool
和SingleThreadScheduledExecutor
:使用的无界的延迟阻塞队列DelayedWorkQueue
,任务队列最大长度为Integer.MAX_VALUE
,可能堆积大量的请求,从而导致 OOM。
下面带大家看一个简单的例子:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
import java.util.concurrent.*;
public class ThreadPoolExample {
public static void main(String[] args) {
// 使用Executors创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 提交大量任务
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executorService.submit(() -> {
try {
Thread.sleep(10000); // 假设任务执行时间很长
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 这里没有关闭线程池,所以线程池中的线程会一直存在
// 实际上,即使关闭线程池,由于任务队列堆积,也可能导致资源无法回收
}
}
在上面的例子中,我们创建了一个固定大小为10的线程池,然后向它提交了几乎无穷多的任务。由于每个任务都执行了很长时间,并且线程池的大小是固定的,newFixedThreadPool采用的是无界队列,而新的任务会不断提交,这可能导致内存耗尽或任务被拒绝。
为了避免这种情况,我们可以使用ThreadPoolExecutor
来创建线程池,并明确指定线程池的大小、队列大小以及拒绝策略等参数。
import java.util.concurrent.*;
public class ThreadPoolExampleWithThreadPoolExecutor {
public static void main(String[] args) {
// 使用ThreadPoolExecutor创建线程池
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 60L;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler
);
// 提交任务(省略了任务提交的代码)
// 关闭线程池
threadPoolExecutor.shutdown();
}
}
在这个例子中,我们明确指定了线程池的核心线程数、最大线程数、队列大小等参数,以及拒绝策略。这样,我们可以更好地控制线程池的行为,避免资源耗尽和OOM错误。