java 基础 | 自定义 java 线程池

本贴最后更新于 1560 天前,其中的信息可能已经时移俗易

javaDEMO

Java 基础 Demo 站: https://www.javastudy.cloud
Java 中高级开发博客: https://www.lixiang.red
Java 学习公众号: java 技术大本营
java_subscribe

线程池创建的参数

创建线程的各种方式中我们有讲到过通过创建线程池来完成异步操作,但实际上 jdk 提供的 Executors 来创建线程池都还有些缺陷,线程池有以下几个参数: 代码节选自源码 ThreadPoolExecutor.java 的构造函数

   public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

corePoolSize: 线程池中线程的个数,最少的个数,即使是空闲的,也会存在
maximumPoolSize: 线程池中允许的连接的最大个数
keepAliveTime: corePoolSize 之外的线程,在没有任务时,最大存活时间
unit: keepAlveTime 的时间单位
workQueue: 在任务还没有执行前,保存 Runnable 任务的地方,也就是待执行任务队列
threadFactory: 线程工厂,可自定义线程生成的方式,可以自定义名字等等
handler:在线程池和队列满的时候,如何处理新到来的任务

jdk 自带线程池的缺陷

自带的线程池主要是通过 Executors 来初始化.

newCachedThreadPool

通过 Executors.newCachedThreadPool()初始化的线程池如下文所示,可以看到 maximumPoolSize 的值是 Integer.MAX_VALUE,这就意味着线程池里面的线程没有上限,会一直新建到 OOM.

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

newFixedThreadPool

通过 Executors.newFixedThreadPool 新建的线程池,我们可以看到 workQueue 这个参数传的是 new LinkedBlockingQueue,这个队列没有设置大小,就会导致新任务会一直往里添加,直到 OOM

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

自定义线程池

通过对自带的线程池的分析,我们知道自定义的线程池主要是对池子的最大数量和等待队列的最大数量做好限制,当然还有息定义的失败策略(以后单写个 DEMO 讲)代码如下:

/**
 * @author https://www.javastudy.cloud
 */
public class ThreadPoolTools {

    /** 线程池维护线程的最少数量 */
    private int minPoolSize = 10;

    /** 线程池维护线程的最大数量 */
    private int maxPoolSize = 500;

    /** 线程池维护线程所允许的空闲时间 */
    private int idleSeconds = 1800;

    /** 线程池所使用的缓冲队列 */
    private int queueBlockSize = 100;

    private ThreadPoolExecutor executor;

    public ThreadPoolTools() {
        this.executor = new ThreadPoolExecutor(minPoolSize, maxPoolSize, idleSeconds,
                TimeUnit.SECONDS, /* 时间单位,秒 */
                new ArrayBlockingQueue<Runnable>(queueBlockSize),
                new ThreadPoolExecutor.CallerRunsPolicy()); /* 重试添加当前加入失败的任务 */
    }

    public void execute(Runnable task) {
        executor.execute(task);
    }

    public <T> Future<T> submit(Callable<T> task){
        return executor.submit(task);
    }
}

DEMO 总评

线程池的使用在实际开发中用到的还是挺多的,在小型开发中使用系统自带的线程池是没问题的,但有时候在生产环境中,特别是同步一些东西的时候,量级比较大,这时候使用系统自带的线程池难免会有些问题,这时候就需要自定义的线程池了,加油吧,少年!!

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3167 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • RustFisher

    想请教一下,线程池核心线程数和最大线程数的数量应该怎么定呢?

  • zc1249274251

    看业务场景,假如是计算密集型 核心线程数为 CPU 数 +1,I/O 密集型:核心线程数为 N*CPU(N>=1),最大线程数 这个没界定 一般可以根据你的核心线程来参考 N 倍于核心 一点拙见,请轻拍

  • someone
    作者

    看楼上哥们的回复,很到位了, 分计算和 IO 两种类型, 这个公式是现在比较通用的公式

  • someone
    作者

    大佬大佬, 点评的很到位, 感谢大佬支持捧场