创建方法:Java原生创建线程池与Spring创建线程池
Java原生创建线程池:
一、手动创建ThreadPollExecutor
java
// Java原生线程池核心构造方法
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
int corePoolSize, // 核心参数1:核心线程数(常驻线程数)
int maximumPoolSize, // 核心参数2:最大线程数(线程池能创建的最大线程数)
long keepAliveTime, // 核心参数3:空闲线程存活时间
TimeUnit unit, // 核心参数4:存活时间的单位(秒/毫秒等)
BlockingQueue<Runnable> workQueue, // 核心参数5:任务阻塞队列(核心线程满了放这里)
ThreadFactory threadFactory, // 核心参数6:线程工厂(自定义线程名称、优先级等)
RejectedExecutionHandler handler // 核心参数7:拒绝策略(队列满+线程满时的处理方式)
);
二、Spring创建线程池
核心类是ThreadPoolTaskExecutor。
纯注解方式(@Configuration+@Bean,SpringBoot首选)
代码示例:
步骤一:编写线程类的核心配置类:
java
@Configuration
public class SpringThreadPoolConfig {
@Bean("customThreadPool")
public Executor customThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(10);
executor.setKeepAliveSeconds(30);
executor.setThreadNamePrefix("SPRING-THREAD-POOL-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化线程池(必须调用,否则线程池不生效)
executor.initialize();
return executor;
}
}
步骤二:业务代码中注入并使用线程池
java
@Service
public class ThreadPoolService {
// 注入线程池:@Qualifier指定Bean的名称,避免多个线程池时注入失败
@Autowired
@Qualifier("customThreadPool")
private Executor customThreadPool;
// 业务方法中执行异步任务
public void doAsyncTask() {
for (int i = 1; i <= 5; i++) {
int finalI = i;
customThreadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 执行异步任务:" + finalI);
try { Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}
});
}
}
}
三、Spring线程池(@Async异步注解)
步骤1:在配置类上添加@EnbaleAsync注解(开启异步支持)
java
@Configuration
@EnableAsync
public class SpringThreadPoolConfig {
@Bean("customThreadPool")
public Executor customThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(10);
executor.setKeepAliveSeconds(30);
executor.setThreadNamePrefix("SPRING-THREAD-POOL-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
步骤2:在业务方法上添加@Async(线程池Bean名)注解
java
@Service
public class AsyncTaskService {
/**
* 被@Async注解的方法,会被自动提交到指定的线程池异步执行
* 无需手动调用线程池,Spring自动处理,无感知!
*/
@Async("customThreadPool")
public void doAsyncTask(int taskId) {
System.out.println(Thread.currentThread().getName() + " 执行异步任务:" + taskId);
try { Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}
}
}
步骤3:调用该方法即可(同步调用,异步执行)
java
@Controller
public class TaskController {
@Autowired
private AsyncTaskService asyncTaskService;
@GetMapping("/task")
public String doTask() {
for (int i = 1; i <= 5; i++) {
// 同步调用,但方法内部会异步执行
asyncTaskService.doAsyncTask(i);
}
return "success";
}
}
线程池的种类:
1、newCachedThreadPool
创建一个可缓存线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程。当需要增加的时候,可以灵活的添加新的线程,不会对线程的长度做出任何限制。
2、newFixedThreadPool
创建一个定长线程池,可以控制线程最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool
创建一个固定长度的线程池,支持定时的以及周期性的任务执行
4、newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来代替它,它保证前一项任务执行完毕后才执行后一项。保证所有任务按照指定顺序执行。
线程池的拒绝策略:
AbortPolicy,默认
线程池的默认拒绝策略,如果线程池满了丢掉这个任务并且抛出RejectedExecutionExcepitio异常
DiscardPolicy
是AbortPolicy的silent版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。
DiscardOldestPolicy
丢弃最老的。如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
CallerRunsPolicy
如果添加到线程池失败,那么调用线程会自己去执行该任务,不会等待线程池中的线程去执行。