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

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

  • [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

相关推荐
侠客行03174 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪4 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术6 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚6 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎7 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰7 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码7 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚7 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂7 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
pas1367 小时前
41-parse的实现原理&有限状态机
开发语言·前端·javascript