Java——全局线程池
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