Java——全局线程池

Java——全局线程池

1. 为什么要全局线程池

通常在项目中使用线程池时,不会直接在方法中或类中直接创建,这样太浪费内存了。普遍的做法是定义个全局线程池,然后提供给项目需要的地方使用。

2. 带有生命周期管理的全局线程池实现

全局线程池所需的功能:

  1. 线程池单例,如果不是单例那就跟在任何地方创建线程池没区别了,所以一定要保持单例;
  2. 线程池通用方法,比如提交任务,延迟执行任务,定时执行任务等。

一般从这两方面实现,但这里加多个功能就是线程池生命周期的管理,就是当应用正常关闭时,线程池需要优雅地关闭,将执行完其中的任务。

在这里插入图片描述

首先看线程池工厂类,这里分了普通的线程池和带有生命周期的线程池,线程池类型分别有单线程、固定线程、定时任务线程池。

ExecutorFactory

/**
 * 线程池工厂
 * @author Tarzan写bug
 * @since 2022/09/08
 */
public class ExecutorFactory {

    /**
     * 单线程线程池
     * @return
     */
    public static ExecutorService newSingleExecutorService() {
        return Executors.newFixedThreadPool(1);
    }

    /**
     * 单线程线程池
     * @param threadFactory 线程工厂
     * @return
     */
    public static ExecutorService newSingleExecutorService(ThreadFactory threadFactory) {
        return Executors.newFixedThreadPool(1, threadFactory);
    }

    /**
     * 固定线程先线程池
     * @param threadNum 线程数量
     * @return
     */
    public static ExecutorService newFixedExecutorService(int threadNum) {
        return Executors.newFixedThreadPool(threadNum);
    }

    /**
     * 固定线程线程池
     * @param threadNum 线程数量
     * @param threadFactory 线程工厂
     * @return
     */
    public static ExecutorService newFixedExecutorService(int threadNum, ThreadFactory threadFactory) {
        return Executors.newFixedThreadPool(threadNum, threadFactory);
    }

    /**
     * 单线程定时任务线程池
     * @return
     */
    public static ExecutorService newSingleScheduleExecutorService() {
        return Executors.newScheduledThreadPool(1);
    }

    /**
     * 单线程定时任务线程池
     * @param threadFactory 线程工厂
     * @return
     */
    public static ExecutorService newSingleScheduleExecutorService(ThreadFactory threadFactory) {
        return Executors.newScheduledThreadPool(1, threadFactory);
    }

    /**
     * 固定线程定时任务线程池
     * @param threadNum 线程数量
     * @return
     */
    public static ExecutorService newScheduleExecutorService(int threadNum) {
        return Executors.newScheduledThreadPool(threadNum);
    }

    /**
     * 固定线程定时任务线程池
     * @param threadNum 线程数量
     * @param threadFactory 线程工厂
     * @return
     */
    public static ExecutorService newScheduleExecutorService(int threadNum, ThreadFactory threadFactory) {
        return Executors.newScheduledThreadPool(threadNum, threadFactory);
    }

    /**
     * 带有生命周期的线程池
     */
    public static class Managed {

        /**
         * 单线程线程池
         * @return
         */
        public static ExecutorService newSingleExecutorService() {
            ExecutorService executorService = Executors.newFixedThreadPool(1);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 单线程线程池
         * @param threadFactory 线程工厂
         * @return
         */
        public static ExecutorService newSingleExecutorService(ThreadFactory threadFactory) {
            ExecutorService executorService = Executors.newFixedThreadPool(1, threadFactory);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 固定线程线程池
         * @param threadNum 线程数量
         * @return
         */
        public static ExecutorService newFixedExecutorService(int threadNum) {
            ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 固定线程线程池
         * @param threadNum 线程数量
         * @param threadFactory 线程工厂
         * @return
         */
        public static ExecutorService newFixedExecutorService(int threadNum, ThreadFactory threadFactory) {
            ExecutorService executorService = Executors.newFixedThreadPool(threadNum, threadFactory);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 单线程定时任务线程池
         * @return
         */
        public static ExecutorService newSingleScheduleExecutorService() {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 单线程定时任务线程池
         * @param threadFactory 线程工厂
         * @return
         */
        public static ExecutorService newSingleScheduleExecutorService(ThreadFactory threadFactory) {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, threadFactory);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 固定线程线程池
         * @param threadNum 线程数量
         * @return
         */
        public static ScheduledExecutorService newScheduleExecutorService(int threadNum) {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(threadNum);
            ThreadPoolManager.register(executorService);
            return executorService;
        }

        /**
         * 固定线程线程池
         * @param threadNum 线程数量
         * @param threadFactory 线程工厂
         * @return
         */
        public static ScheduledExecutorService newScheduleExecutorService(int threadNum, ThreadFactory threadFactory) {
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(threadNum, threadFactory);
            ThreadPoolManager.register(executorService);
            return executorService;
        }
    }
}

生命周期管理的线程池会注册到ThreadPoolManager中,该类初始化时会向Runtime.getRuntime()中添加应用关闭回调线程,而这个回调线程执行优雅关闭线程池集合。

ThreadPoolManager

/**
 * 线程池生命周期管理
 * @author Tarzan写bug
 * @since 2022/09/08
 */
public class ThreadPoolManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolManager.class);

    /**
     * 线程池集合
     */
    private static Set<ExecutorService> managedExecutors = new HashSet<>();

    /**
     * 对象锁,防并发写
     */
    private static final Object LOCK = new Object();

    /**
     * CAS
     */
    private static final AtomicBoolean CLOSED = new AtomicBoolean(false);

    /**
     * 单例
     */
    private static final ThreadPoolManager INSTANCE = new ThreadPoolManager();

    private ThreadPoolManager() {}

    static {
        // 应用关闭时,优雅关闭线程池
        ThreadUtil.addShutdownHook(new Runnable() {
            @Override
            public void run() {
                LOGGER.warn("start shutdown thread pool");
                shutdown();
                LOGGER.warn("shutdown thread pool finish");
            }
        });
    }

    /**
     * 单例
     * @return
     */
    public static ThreadPoolManager getInstance() {
        return INSTANCE;
    }

    /**
     * 注册线程池
     * @param executorService
     */
    public static void register(ExecutorService executorService) {
        synchronized (LOCK) {
            managedExecutors.add(executorService);
        }
    }

    /**
     * 注销线程池
     * @param executorService
     */
    public static void deregister(ExecutorService executorService) {
        synchronized (LOCK) {
            managedExecutors.remove(executorService);
        }
    }

    /**
     * 关闭线程池
     */
    private static void shutdown() {
        // CAS防止多次调用
        if (!CLOSED.compareAndSet(false, true)) {
            return;
        }
        for (ExecutorService managedExecutor : managedExecutors) {
            ThreadUtil.shutdownThreadPool(managedExecutor);
        }
    }
}

ThreadUtil提供应用关闭线程回调,和优雅关闭线程池方法

/**
 * 线程工具类
 * @author Tarzan写bug
 * @since 2022/09/08
 */
public class ThreadUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadUtil.class);

    private ThreadUtil() {}

    /**
     * 程序关闭时添加回调线程
     * @param runnable
     */
    public static void addShutdownHook(Runnable runnable) {
        Runtime.getRuntime().addShutdownHook(new Thread(runnable));
    }

    /**
     * 关闭线程池
     * @param executorService 线程池
     */
    public static void shutdownThreadPool(ExecutorService executorService) {
        executorService.shutdown();
        int retry = 3;
        if (retry > 0) {
            retry--;
            try {
                if (executorService.awaitTermination(1, TimeUnit.SECONDS)) {
                    return;
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.interrupted();
            } catch (Throwable ex) {
                LOGGER.error("shutdown thread pool has error: {}", ex);
            }
        }
        executorService.shutdownNow();
    }
}

接着就是提供给项目开发人员直接调用的全局线程池GlobalExecutor

/**
 * 全局线程池
 * @author Tarzan写bug
 * @since 2022/09/08
 */
public class GlobalExecutor {

    /**
     * 普通线程池
     */
    private static final ExecutorService COMMON_EXECUTOR = ExecutorFactory.Managed
            .newFixedExecutorService(Runtime.getRuntime().availableProcessors(),
                    new NameThreadFactory("com.mountain.threadpool.common"));

    /**
     * 定时线程池
     */
    private static final ScheduledExecutorService COMMON_SCHEDULE_EXECUTOR = ExecutorFactory.Managed
            .newScheduleExecutorService(Runtime.getRuntime().availableProcessors(),
                    new NameThreadFactory("com.mountain.threadpool.commmon.schedule"));

    private GlobalExecutor() {}

    /**
     * 提交任务到线程池中执行
     * @param runnable 线程任务
     */
    public static void submitCommonExecutor(Runnable runnable) {
        COMMON_EXECUTOR.submit(runnable);
    }

    /**
     * 提交任务到线程池中延迟执行
     * @param runnable 线程任务
     * @param delay 延迟时间
     * @param unit 时间单位
     */
    public static void scheduleCommonExecutor(Runnable runnable, long delay, TimeUnit unit) {
        COMMON_SCHEDULE_EXECUTOR.schedule(runnable, delay, unit);
    }

    /**
     * 提交任务到线程池中定时执行
     * @param runnable 线程任务
     * @param delay 延迟时间
     * @param fixed 定时时间
     * @param unit 时间单位
     */
    public static void scheduleWithFixedDelay(Runnable runnable, long delay, long fixed, TimeUnit unit) {
        COMMON_SCHEDULE_EXECUTOR.scheduleWithFixedDelay(runnable, delay, fixed, unit);
    }
}

3. 总结

全局线程池还要注意线程池中最大线程数量和阻塞队列的实现。由于最近在研究Nacos,所以上述实现借鉴了Nacos的源码。全局线程池还有很多实现方式,欢迎讨论和学习。上述代码收录在https://gitee.com/ouwenrts/tuyere.git.



谢谢阅读,就分享到这,未完待续…

欢迎同频共振的那一部分人

作者公众号:Tarzan写bug

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值