# Java线程池实战,别再new Thread了

每次需要异步执行任务就new Thread()?这在生产环境是灾难。

线程的创建和销毁是有开销的,无限制创建线程会导致资源耗尽。Java线程池就是来解决这个问题的------复用线程、控制并发数、管理任务队列。

为什么不用new Thread

java 复制代码
// 每次请求都创建新线程 ------ 大忌
public void handleRequest(Request req) {
    new Thread(() -> {
        process(req);
    }).start();
}
// 1000个并发请求 = 1000个线程 = 内存爆炸
问题 说明
资源浪费 每个线程占用约1MB栈内存
频繁创建销毁 线程创建需要操作系统介入,开销大
无管理 没有队列、没有拒绝策略、没有监控

核心参数

java 复制代码
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4,                          // corePoolSize:核心线程数
    8,                          // maximumPoolSize:最大线程数
    60, TimeUnit.SECONDS,       // keepAliveTime:非核心线程空闲存活时间
    new LinkedBlockingQueue<>(100), // 任务队列
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

任务提交流程:

markdown 复制代码
新任务提交
  ↓
核心线程数满了?
  ├─ 否 → 创建核心线程执行
  └─ 是 ↓
    队列满了?
      ├─ 否 → 放入队列等待
      └─ 是 ↓
        最大线程数满了?
          ├─ 否 → 创建非核心线程执行
          └─ 是 → 执行拒绝策略

四种拒绝策略

策略 行为
AbortPolicy(默认) 抛出RejectedExecutionException
CallerRunsPolicy 让提交任务的线程自己执行
DiscardPolicy 直接丢弃,不报错
DiscardOldestPolicy 丢弃队列中最老的任务

四种内置线程池

java 复制代码
// 固定大小线程池
ExecutorService fixed = Executors.newFixedThreadPool(4);

// 缓存线程池(来多少创建多少,空闲60s回收)
ExecutorService cached = Executors.newCachedThreadPool();

// 单线程池(保证任务顺序执行)
ExecutorService single = Executors.newSingleThreadExecutor();

// 定时线程池
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(2);
scheduled.scheduleAtFixedRate(() -> {
    System.out.println("每10秒执行一次");
}, 0, 10, TimeUnit.SECONDS);

注意:阿里规范禁止使用Executors创建线程池,因为:

  • newFixedThreadPool和newSingleThreadExecutor用的是无界队列(LinkedBlockingQueue无参构造),任务堆积可能导致OOM
  • newCachedThreadPool最大线程数是Integer.MAX_VALUE,可能创建大量线程导致OOM

推荐直接用ThreadPoolExecutor手动创建,参数自己控制。

实际项目中的配置

java 复制代码
@Configuration
public class ThreadPoolConfig {

    @Bean("businessPool")
    public ThreadPoolExecutor businessPool() {
        return new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() * 2, // CPU核心数×2
            Runtime.getRuntime().availableProcessors() * 4,
            60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            new ThreadFactoryBuilder().setNameFormat("biz-pool-%d").build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
}

// 使用
@Service
public class OrderService {

    @Autowired
    @Qualifier("businessPool")
    private ThreadPoolExecutor executor;

    public void createOrder(Order order) {
        CompletableFuture.supplyAsync(() -> {
            // 异步处理
            return processOrder(order);
        }, executor).thenAccept(result -> {
            log.info("订单处理完成: {}", result);
        });
    }
}

线程池大小怎么定

任务类型 推荐线程数 理由
CPU密集型 CPU核心数 + 1 减少线程切换开销
IO密集型 CPU核心数 × 2 ~ × N 线程大部分时间在等IO
混合型 根据任务比例调整 IO多就多开线程
java 复制代码
// 获取CPU核心数
int cpuCores = Runtime.getRuntime().availableProcessors();

// IO密集型经验公式
int ioThreads = (int)(cpuCores / (1 - 阻塞系数));
// 阻塞系数 = 线程等待时间 / (线程等待时间 + 线程计算时间)

优雅关闭

java 复制代码
// 优雅关闭线程池
public void shutdown() {
    executor.shutdown(); // 不再接受新任务,但会处理完队列中的任务
    try {
        if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
            executor.shutdownNow(); // 超时强制关闭
        }
    } catch (InterruptedException e) {
        executor.shutdownNow();
    }
}

线程池是Java并发编程的标配。记住:永远用ThreadPoolExecutor手动创建,别用Executors的快捷方法。参数根据业务场景调,别用默认值。

你们项目的线程池参数是怎么设的?

相关推荐
ee又momo2 小时前
# 深入理解Java注解,从使用到自定义
java
霸道流氓气质3 小时前
AI智能博客平台实战:RAG增强写作、多Agent协作与语义检索的Vue3 + Spring AI全栈实现
java·人工智能·spring
打工仔折腾 AI3 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
哦虎!3 小时前
【JavaEE】网络原理 - TCP/IP
java
东风微鸣3 小时前
把 Tailscale 接进 Prometheus 监控
java·数据库·prometheus
看浪的路人3 小时前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
大侠归来3 小时前
事务能回滚吗?Pipeline 算事务吗?
java·数据库·oracle
蜗牛互联网3 小时前
Python调用Gemini Structured Outputs实现工单路由门禁
java·开发语言·人工智能·python
Wang's Blog3 小时前
Java 项目实战: 交友项目 - 产品定位、功能模块与客户端原型解读
java·开发语言·交友