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

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

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

相关推荐
黑牛先生几秒前
【Qt】信号与槽
开发语言·qt
风象南1 分钟前
SpringBoot防重放攻击的5种实现方案
java·spring boot·后端
橙子199110161 小时前
Kotlin 中的 Object
android·开发语言·kotlin
callJJ1 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(1)
java·开发语言·spring boot·后端·spring·restful·ioc di
Python开发吖2 小时前
【已解决】python的kafka-python包连接kafka报认证失败
开发语言·python·kafka
@老蝴5 小时前
C语言 — 通讯录模拟实现
c语言·开发语言·算法
编程乐学(Arfan开发工程师)6 小时前
56、原生组件注入-原生注解与Spring方式注入
java·前端·后端·spring·tensorflow·bug·lua
♚卜卦7 小时前
面向对象 设计模式简述(1.创建型模式)
开发语言·设计模式
安全系统学习7 小时前
网络安全之RCE简单分析
开发语言·python·算法·安全·web安全