创建线程池的常用方法
1、使用Executors进行创建
ExecutorService poo1 = Executors.newFixedThreadPool(10);
ExecutorService pool = Executors.newSingleThreadExecutor();
ExecutorService poo1 = Executors.newCachedThreadPool();
ExecutorService poo1 = Executors.newScheduledThreadPool(10);
2、通过ThreadPoolExecutor创建线程池
// threadFactory 创建线程的工厂,通常会重新指定线程名,方便debug
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("这是线程%d - ").build();
ExecutorService pool = new ThreadPoolExecutor(3, 6, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(3), threadFactory, new ThreadPoolExecutor.AbortPolicy());
以上是一个简单的实例,表示创建一个核心线程数为3,最大线程数为6,超时0s就进行回收,缓存队列容量为3,并使用AbortPolicy的拒绝策略
1、配置TaskExecutor
这里直接将线程池注入
创建ThreadPoolConfig类,注意,需标记@EnableAsync
@Configuration
@EnableAsync
public class ThreadPoolConfig {
//其他
@Bean
public Executor defaultThreadPool() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
executor.setPoolSize(线程大小);
executor.setThreadPriority(优先级);
executor.setThreadNamePrefix(名称前缀);
executor.initialize();
return executor;
}
}
配置1、自定义配置
@Configuration
//@EnableAsync
public class ThreadPoolConfig {
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
/**
* 获得Java虚拟机可用的处理器个数 + 1
*/
private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;
@Value("${async.executor.thread.core_pool_size:0}")
public static int corePoolSizeConfig;
// 核心线程池大小
public static int corePoolSize = corePoolSizeConfig ==0 ? THREADS : corePoolSizeConfig;
// 最大可创建的线程数
//@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize = 2 * THREADS;;
// 队列最大长度
//@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity = 1024;
// 线程池维护线程所允许的空闲时间
//@Value("${async.executor.thread.keep_alive_seconds}")
private int keepAliveSeconds = 300;
//线程池名前缀
//@Value("${async.executor.thread.threadNamePrefix}")
private static final String threadNamePrefix = "Async-Service-";
@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(maxPoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务(无线程可用)的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
4、Async调用
执行代码和任务效率比较差的时候,可以考虑使用Async进行异步调用。
注意:
1、static 方法使用@Async注解无效
2、异步方法和调用异步方法不能在同一个类里面
使用配置:
@EnableAsync
@Configuration
class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置核心线程数
executor.setCorePoolSize(10);
//设置最大线程数
executor.setMaxPoolSize(20);
//线程池所使用的缓冲队列
executor.setQueueCapacity(200);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止
executor.setAwaitTerminationSeconds(60);
return executor;
}
}
使用方法:
1、在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式:
import java.util.Random;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
publicclass Task2 {
//定义一个随机对象.
publicstatic Random random =new Random();
//任务一;
@Async
publicvoid doTaskOne() throws Exception {
System.out.println("开始做任务一");
longstart = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
longend = System.currentTimeMillis();
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
}
//任务二;
@Async
publicvoid doTaskTwo() throws Exception {
System.out.println("开始做任务二");
longstart = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
longend = System.currentTimeMillis();
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
}
//任务3;
@Async
publicvoid doTaskThree() throws Exception {
System.out.println("开始做任务三");
longstart = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
longend = System.currentTimeMillis();
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
}
}
3、为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:
@EnableAsync
publicclass App {
//省略其它代码…
}
3、编写测试方法:
//测试task2.
@RequestMapping("/task2")
public String task2() throws Exception{
task2.doTaskOne();
task2.doTaskTwo();
task2.doTaskThree();
return"task2";
}
4、等待多个异步任务执行完应该怎么办
public class AsyncTask {
@Async
public Future<String> task1() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(1000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task1执行完毕");
}
@Async
public Future<String> task2() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(2000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task2执行完毕");
}
@Async
public Future<String> task3() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(3000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task3执行完毕");
}
}
使用时:
@RestController
public class AsyncTaskController {
@Autowired
private AsyncTask asyncTask;
@RequestMapping("")
public String doTask() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Future<String> task1 = asyncTask.task1();
Future<String> task2 = asyncTask.task2();
Future<String> task3 = asyncTask.task3();
String result = null;
for (;;) {
if(task1.isDone() && task2.isDone() && task3.isDone()) {
// 三个任务都调用完成,退出循环等待
break;
}
Thread.sleep(1000);
}
long currentTimeMillis1 = System.currentTimeMillis();
result = "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";
return result;
}
}