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