我们都知道JDK1.5之后提供了ThreadPoolExecutor类,可以用来自定义线程池。
线程池有很多好处,比如:
减少资源消耗,避免频繁创建和销毁线程,可以直接复用已有线程。
提供速度,任务来了之后,因为线程已经存在,可以直接使用。
提高线程的可管理性。线程是非常宝贵的资源。如果创建的线程过多,不仅会消耗系统资源,甚至会影响系统的稳定性。
使用线程池,可以非常方便地创建、管理和监控线程。
该类包含许多静态方法:
newCachedThreadPool: 创建一个可缓冲线程。如果线程池的大小超过处理需要,可以灵活回收空闲线程。如果没有回收,则创建一个新线程。
newFixedThreadPool:创建一个固定大小的线程池。如果任务数量超过线程池大小,则将多余的任务放入队列中。
newScheduledThreadPool:创建一个固定大小的线程池,可以执行定时的周期性任务。
newSingleThreadExecutor:创建一个只有一个线程的线程池,保证所有任务按顺序安装和执行。
在高并发场景下,如果使用这些静态方法来创建线程池,会出现一些问题。
那么,让我们看看存在哪些问题。
newFixedThreadPool:允许请求的队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM。
newSingleThreadExecutor:请求允许的队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM。
newCachedThreadPool: 允许创建的线程数为Integer.MAX_VALUE,可能会创建大量线程,导致OOM。
那么我们应该怎么做呢?
建议先使用ThreadPoolExecutor类,我们自定义线程池。
具体代码如下:
ExecutorService threadPool = <b>new</b> ThreadPoolExecutor(
8, <font><i>//The number of core threads in the corePoolSize thread pool</i></font><font>
10, </font><font><i>//maximumPoolSize The maximum number of threads in the thread pool</i></font><font>
60, </font><font><i>//The maximum idle time of threads in the thread pool, after which idle threads will be recycled</i></font><font>
TimeUnit.SECONDS,</font><font><i>//time unit</i></font><font>
<b>new</b> ArrayBlockingQueue(500), </font><font><i>//queue</i></font><font>
<b>new</b> ThreadPoolExecutor.CallerRunsPolicy()); </font><font><i>//rejection policy</i></font><font>
</font>
顺便说一句,如果是一些低并发的场景,使用Executors类创建线程池也不是不行,也不是所有场景都可以使用。
在这些低并发场景中,很难出现OOM问题,所以我们需要根据实际业务场景进行选择。