【线程与线程池】线程数设置(四)

【线程与线程池】线程数设置

  • [0. 全局使用一个线程池](#0. 全局使用一个线程池)
  • [1. 按照任务类型对线程池进行分类](#1. 按照任务类型对线程池进行分类)
    • [1.1 Netty的IO处理任务,就是典型的IO密集型任务](#1.1 Netty的IO处理任务,就是典型的IO密集型任务)
  • [2. 混合型任务创建线程池时,如何确定线程数](#2. 混合型任务创建线程池时,如何确定线程数)

0. 全局使用一个线程池

java 复制代码
import java.util.concurrent.*;

public class GlobalThreadPool {

    // 单例线程池
    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
            10,                      // 核心线程数
            50,                      // 最大线程数
            60L, TimeUnit.SECONDS,   // 空闲线程最大存活时间
            new LinkedBlockingQueue<>(1000), // 工作队列
            new ThreadFactory() {
                private final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
                private int counter = 0;

                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = defaultFactory.newThread(r);
                    thread.setName("global-thread-" + counter++);
                    return thread;
                }
            },
            new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略
    );

    private GlobalThreadPool() {
        // 私有构造防止实例化
    }

    public static ThreadPoolExecutor getExecutor() {
        return EXECUTOR;
    }
}

业务中使用

java 复制代码
import java.util.concurrent.Future;

public class Demo {
    public void runTask() {
        Runnable task = () -> {
            System.out.println("执行任务:" + Thread.currentThread().getName());
        };

        // 提交任务
        GlobalThreadPool.getExecutor().execute(task);
    }
}

也可以使用 submit() 获取 Future 对象:

java 复制代码
Future<String> future = GlobalThreadPool.getExecutor().submit(() -> {
    // 业务逻辑
    return "result";
});

优雅关闭线程池(如在应用退出时)

java 复制代码
public class ShutdownHook {
    public static void register() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("关闭全局线程池...");
            GlobalThreadPool.getExecutor().shutdown();
            try {
                if (!GlobalThreadPool.getExecutor().awaitTermination(60, TimeUnit.SECONDS)) {
                    GlobalThreadPool.getExecutor().shutdownNow();
                }
            } catch (InterruptedException e) {
                GlobalThreadPool.getExecutor().shutdownNow();
            }
        }));
    }
}

在 Spring Boot 中可以在 @PostConstruct 中调用注册:

@Component
public class AppInitializer {

    @PostConstruct
    public void init() {
        ShutdownHook.register();
    }
}

另一种方法

java 复制代码
在 Spring Boot 中,更建议使用 Spring 的 @Bean + 注入方式统一线程池,例如:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.util.concurrent.*;

@Configuration
public class ThreadPoolConfig {

    @Value("${threadpool.corePoolSize:10}")
    private int corePoolSize;

    @Value("${threadpool.maxPoolSize:50}")
    private int maxPoolSize;

    @Value("${threadpool.queueCapacity:1000}")
    private int queueCapacity;

    @Value("${threadpool.keepAliveSeconds:60}")
    private long keepAliveSeconds;

    @Value("${threadpool.threadNamePrefix:global-pool}")
    private String threadNamePrefix;

    @Value("${threadpool.rejectedPolicy:CallerRunsPolicy}")
    private String rejectedPolicy;

    private ThreadPoolExecutor executor;

    @Bean(name = "globalExecutor", destroyMethod = "") // 禁用 Spring 自动销毁,手动控制
    public Executor globalExecutor() {
        executor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveSeconds, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                new CustomThreadFactory(threadNamePrefix),
                getRejectedExecutionHandler()
        );
        return executor;
    }

    @PreDestroy
    public void shutdown() {
        if (executor != null) {
            System.out.println("[ThreadPoolConfig] 正在关闭线程池...");
            executor.shutdown();
            try {
                if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                    System.out.println("[ThreadPoolConfig] 超时未关闭,强制关闭线程池");
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
                System.out.println("[ThreadPoolConfig] 线程池关闭被中断,已强制关闭");
            }
            System.out.println("[ThreadPoolConfig] 线程池已成功关闭");
        }
    }

    private RejectedExecutionHandler getRejectedExecutionHandler() {
        switch (rejectedPolicy) {
            case "AbortPolicy":
                return new ThreadPoolExecutor.AbortPolicy();
            case "DiscardPolicy":
                return new ThreadPoolExecutor.DiscardPolicy();
            case "DiscardOldestPolicy":
                return new ThreadPoolExecutor.DiscardOldestPolicy();
            case "CallerRunsPolicy":
            default:
                return new ThreadPoolExecutor.CallerRunsPolicy();
        }
    }

    private static class CustomThreadFactory implements ThreadFactory {
        private final String prefix;
        private final ThreadGroup group;
        private int count = 1;

        CustomThreadFactory(String prefix) {
            this.prefix = prefix;
            this.group = Thread.currentThread().getThreadGroup();
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, prefix + "-thread-" + count++);
            t.setDaemon(false);
            t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
}

使用方式:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.Executor;

@Service
public class TaskService {

    private final Executor globalExecutor;

    @Autowired
    public TaskService(@Qualifier("globalExecutor") Executor globalExecutor) {
        this.globalExecutor = globalExecutor;
    }

    public void submitTasks() {
        for (int i = 1; i <= 5; i++) {
            int taskId = i;
            globalExecutor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 正在执行任务: " + taskId);
                try {
                    Thread.sleep(2000);  // 模拟任务执行耗时
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println(Thread.currentThread().getName() + " 完成任务: " + taskId);
            });
        }
    }
}


@Qualifier("globalExecutor") 的作用是指定注入哪个具体的 Bean。是否必须加它,取决于你项目中是否存在多个同类型的 Bean。

启动入口调用(例如在 Spring Boot 主类或测试里)

java 复制代码
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class Runner implements CommandLineRunner {

    private final TaskService taskService;

    public Runner(TaskService taskService) {
        this.taskService = taskService;
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("提交任务到全局线程池...");
        taskService.submitTasks();
    }
}

1. 按照任务类型对线程池进行分类



1.1 Netty的IO处理任务,就是典型的IO密集型任务


2. 混合型任务创建线程池时,如何确定线程数

P10

相关推荐
Fireworkitte1 小时前
Apache POI 详解 - Java 操作 Excel/Word/PPT
java·apache·excel
weixin-a153003083161 小时前
【playwright篇】教程(十七)[html元素知识]
java·前端·html
DCTANT1 小时前
【原创】国产化适配-全量迁移MySQL数据到OpenGauss数据库
java·数据库·spring boot·mysql·opengauss
Touper.2 小时前
SpringBoot -- 自动配置原理
java·spring boot·后端
黄雪超2 小时前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice2 小时前
对象的finalization机制Test
java·开发语言·jvm
思则变2 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
lijingguang2 小时前
在C#中根据URL下载文件并保存到本地,可以使用以下方法(推荐使用现代异步方式)
开发语言·c#
¥-oriented3 小时前
【C#中路径相关的概念】
开发语言·c#
CoderCodingNo3 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法