-
CompletableFuture 是jdk8进入的一个异步变成工具,可以实现多线程编程。
-
下面记录了一次,多线程处理处理一个业务的例子,并且要等待所有异步子线程执行完成后,主线程才能继续往下执行。
-
supplyAsync:异步线程有返回值; runAsync:异步线程没返回值
-
new ThreadPoolExecutor()的各个参数的意义:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}
corePoolSize:核心线程数。会一直存活,及时没有任务需要执行,除非设置允许核心线程超时的参数。
maximumPoolSize:最大线程数。线程池中允许的最大线程,包含核心线程数。如果请求的线程数大于最大线程数,则会放到阻塞队列中。
keepAliveTime:非核心线程空闲等待时间,超过这个时间没有任务的话,非核心线程会被从线程池中销毁。如果设置为0L的话,则非核心线程执行完任务后如果没有任务的话会立即销毁。
unit:keepAliveTime的时间单位。
workQueue:表示缓存队列。当请求的线程数大于maximumPoolSize时,线程进入 BlockingQueue阻塞队列。
后续示例代码中使用的LinkedBlockingQueue是单向链表,使用锁来控制入队和出队的原子性,两个锁分别控制元素的添加和获取,是一个生产消费模型队列。
threadFactory:表示线程工厂。它用来生产一组相同任务的线程。定义了线程名称。
handler:拒绝策略, 是当任务队列满了,线程池线程数也达到最大了,这个时候,又有任务要执行的时候,执行什么策略进行处理这些任务。有四种策略
(1)AbortPolicy: 中止策略(默认) 直接抛出RejectedExecutionException异常
(2) DiscardPolicy: 丢弃策略 啥都不做,直接丢掉这个任务
(3) DiscardOldestPolicy: 丢弃最早的未处理的任务策略 会丢掉最早未执行的任务,然后重试当前这个任务
(4) CallerRunsPolicy: 调用者执行策略 如果executor没有关闭,会在执行execute方法的线程中直接调用任务的run方法。如果executor关闭了,这个任务就会被丢弃不执行。
一些总结:
线程池一般建议设置为全局的,不要定义到方法内部,这样会出现很多问题也失去了线程池中线程复用的初心。这样一来如何规划线程池的使用很重要,一般会按照同一个业务模块内的使用同一个线程池。并且这样全局的线程池是不shutdown()的。
这样的话核心线程数corePoolSize一定要定义好,因为核心线程数是会一直存在池中的。
线程池不定义在方法内部,如果非得写也不要忘了shutdown();否则上线后并发高了每个线程都创建线程池一定会出问题。
@RestController
@RequestMapping(value = "/test")
public class ThreadController {
@Autowired
TaskService taskService;
private static final ExecutorService pool;
static {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("export-pool-%d") //线程名称
.build();
pool = new ThreadPoolExecutor(
4,
10,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(2048),
threadFactory,
new ThreadPoolExecutor.AbortPolicy());
}
public void test() throws ExecutionException, InterruptedException {
List<CompletableFuture<String>> futrueList = new ArrayList<>();
for (int i = 0; i<10;i++){
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
String s = null;
try {
s = taskService.testThread("");
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("标记0:"+Thread.currentThread().getName());
return s;
}, pool);
futrueList.add(future);
}
System.out.println("标记1:"+Thread.currentThread().getName());
CompletableFuture.allOf(futrueList.toArray(new CompletableFuture[futrueList.size()])).join(); // 等待所有子线程的任务执行完毕
System.out.println("标记2:"+Thread.currentThread().getName());
for (CompletableFuture<String> fu : futrueList) {
System.out.println(fu.get());
}
}
运行结果: