线程池与异步编程——语法归纳
一、Java 原生线程池(java.util.concurrent
)
1.1 创建线程池(推荐使用 ThreadPoolExecutor
)
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, // 核心线程数 corePoolSize10, // 最大线程数 maximumPoolSize60L, // 空闲线程存活时间 keepAliveTimeTimeUnit.SECONDS, // 时间单位new LinkedBlockingQueue<>(100), // 队列(有界队列防止 OOM)Executors.defaultThreadFactory(), // 线程工厂new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
如果 线程数已经达到最大值,并且 队列也满了,线程池就没有能力再接新任务了。
这时必须要做一个选择 —— 这就是 拒绝策略。
📌 常见 拒绝策略:
AbortPolicy
:抛异常(默认)。CallerRunsPolicy
:由调用者线程执行任务。DiscardPolicy
:直接丢弃任务。DiscardOldestPolicy
:丢弃最旧任务,执行当前任务。
1.2 使用线程池
executor.execute(() -> System.out.println("执行任务1"));Future<String> future = executor.submit(() -> "任务结果");
System.out.println(future.get()); // 阻塞等待结果executor.shutdown(); // 关闭线程池
1.3 Executors 工厂方法(不推荐生产使用)
Executors.newFixedThreadPool(5); // 固定大小线程池
Executors.newCachedThreadPool(); // 缓存线程池,按需创建
Executors.newSingleThreadExecutor(); // 单线程
Executors.newScheduledThreadPool(5); // 定时/周期任务
👉 问题:这些方法的队列可能是 无界的,容易导致 OOM,所以阿里规范建议直接用 ThreadPoolExecutor
。
二、Spring 线程池(推荐在企业项目中用)
Spring 对线程池做了封装,常用 ThreadPoolTaskExecutor
(基于 Java ThreadPoolExecutor
)。
2.1 配置线程池(Java Config 方式)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
public class ThreadPoolConfig {@Bean("myExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5); // 核心线程数executor.setMaxPoolSize(10); // 最大线程数executor.setQueueCapacity(100); // 队列容量executor.setKeepAliveSeconds(60); // 空闲线程存活时间executor.setThreadNamePrefix("my-thread-"); // 线程名前缀executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());executor.initialize(); // 初始化return executor;}
}
2.2 使用线程池
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;@Service
public class MyService {@Async("myExecutor") // 指定使用哪个线程池public void asyncTask() {System.out.println("执行异步任务:" + Thread.currentThread().getName());}
}
⚡ 记得在启动类开启异步支持:
@EnableAsync
@SpringBootApplication
public class MyApplication { }
2.3 Spring Boot 配置文件方式(更简洁)
application.yml
spring:task:execution:pool:core-size: 5max-size: 10queue-capacity: 100keep-alive: 60sthread-name-prefix: my-thread-
使用时同样写 @Async
注解即可。
三、异步编程
CompletableFuture 是Futrue 的增强版,不阻塞线程,一般搭配线程池使用,执行异步任务。
Future 工作流程
主线程 ── submit(task) ──► 线程池执行task
主线程 ── get() ──(阻塞等待)────────────┐│ 任务完成/异常
主线程 ◄────────────── 返回结果/抛异常 ─┘
CompletableFuture 工作流程
主线程 ── supplyAsync(task) ─► 线程池执行task
主线程 ── thenApply(...) / thenAccept(...)/whenComplete(...) // 只是注册回调,立刻返回(稍后某时)
线程池工作线程:task完成 → 将“完成信号”分派给已注册的回调
异步执行任务,无线程
// thenApply: 有入参有返回(T -> R)
CompletableFuture<Integer> cf =CompletableFuture.supplyAsync(() -> 21).thenApply(x -> x * 2); // -> 42
指定线程池
// 指定线程池
ExecutorService pool = Executors.newFixedThreadPool(8);
CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "hi", pool);