使用 Callable 和 Future 处理异步任务
在实际的并发编程中,通常我们会将 Callable 和 Future 一起使用。Future 是一个表示异步任务结果的容器,可以让我们查询任务是否完成、获取结果、取消任务等操作。结合 ExecutorService 来使用时,Callable 可以更方便地执行异步任务
private static final ExecutorService SHARED_EXECUTOR = Executors.newFixedThreadPool(10);
/**
* 检查电话号码是否在黑名单中
*
* @param vccId 企业ID
* @param phone 电话号码
* @param trunk 中继号码,默认为"0"
* @param callType 呼叫类型,默认为呼入
* @return 如果在黑名单中返回true,否则返回false
*/
@Override
public boolean isPhoneInBlacklist(long vccId, String phone, String trunk, int callType) {
// 创建多个检查任务
List<Callable<Boolean>> tasks = new ArrayList<>();
// 精确匹配检查
tasks.add(() -> {
return false;
});
// 全局精确匹配检查(不指定中继号码)
tasks.add(() -> {
return false;
});
// 并行执行所有检查任务
return executeParallelChecks(tasks);
}
/**
* 执行并行检查任务
*
* @param tasks 检查任务列表
* @return 如果任何一个任务返回true,则返回true
*/
private boolean executeParallelChecks(List<Callable<Boolean>> tasks) {
try {
List<Future<Boolean>> futures = SHARED_EXECUTOR.invokeAll(tasks);
for (Future<Boolean> future : futures) {
if (future.get()) {
return true;
}
}
return false;
} catch (InterruptedException e) {
BLACKLIST_SERVICE_LOG.error("执行黑名单检查时被中断", e);
Thread.currentThread().interrupt(); // 恢复中断状态
return false;
} catch (ExecutionException e) {
BLACKLIST_SERVICE_LOG.error("执行黑名单检查时发生错误", e);
return false;
}
}
异常处理
Callable 的另一个优势在于它允许抛出受检异常。这使得它在处理可能会抛出异常的任务时更为灵活。在并发环境中处理异常是一个关键问题,尤其是在分布式系统或者 I/O 密集型的操作中。通过使用 Callable,我们可以捕获并处理在任务执行过程中可能抛出的任何异常。
Callable<String> task = () -> {
if (new Random().nextBoolean()) {
throw new Exception("任务执行失败");
}
return "任务成功";
};
Future<String> future = executor.submit(task);
try {
String result = future.get();
System.out.println(result);
} catch (ExecutionException e) {
System.out.println("任务抛出异常: " + e.getCause());
}
CompletableFuture
CompletableFuture 是 Java 8 引入的一个强大的异步编程工具类,位于 java.util.concurrent 包中。它扩展了 Future 接口,提供了更丰富的功能来处理异步任务和组合多个异步操作。
主要特性
1. 异步执行:
- 可以通过 supplyAsync()、runAsync() 等方法异步执行任务
2. 链式调用:
- 支持链式调用和函数组合,如 thenApply()、thenCompose()、thenCombine()
- 使用 thenApply() 处理所有异步任务完成后的结果收集
3. 组合多个异步操作:
- allOf() 方法用于等待所有给定的 CompletableFuture 完成
- anyOf() 方法用于等待任意一个 CompletableFuture 完成
4. 异常处理:
- 提供了多种异常处理机制,如 exceptionally()、handle() 等
基本使用方法
runAsync与supplyAsync
// 创建一个已完成的 CompletableFuture
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Hello");
// 创建一个空的 CompletableFuture
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 执行一些任务
System.out.println("执行异步任务");
});
// 创建一个有返回值的 CompletableFuture
CompletableFuture<String> futureWithResult = CompletableFuture.supplyAsync(() -> {
// 执行一些任务并返回结果
return "异步任务结果";
});
- supplyAsync(Supplier<U> supplier):异步执行有返回值的任务
- runAsync(Runnable runnable):异步执行无返回值的任务
- completedFuture(U value):创建一个已完成的 CompletableFuture
获取结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello World");
// 阻塞等待结果
String result = future.get(); // 可能抛出异常
// 或者使用 join() 方法(不抛出受检异常)
String result2 = future.join();
// 设置超时时间
String result3 = future.get(1, TimeUnit.SECONDS);
回调处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
// 使用 thenAccept 处理结果
future.thenAccept(result -> System.out.println("结果: " + result));
// 使用 thenApply 转换结果
CompletableFuture<String> transformedFuture = future.thenApply(result -> result + " World");
// 使用 thenRun 执行不关心结果的任务
future.thenRun(() -> System.out.println("任务完成"));
- thenApply(Function<? super T,? extends U> fn):对结果进行转换
- thenAccept(Consumer<? super T> action):消费结果
- thenRun(Runnable action):执行不依赖于结果的任务
异常处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("发生错误");
}
return "成功";
});
// 使用 exceptionally 处理异常
CompletableFuture<String> handledFuture = future.exceptionally(ex -> {
System.out.println("捕获异常: " + ex.getMessage());
return "默认值";
});
// 使用 handle 处理正常和异常情况
CompletableFuture<String> handledFuture2 = future.handle((result, ex) -> {
if (ex != null) {
System.out.println("处理异常: " + ex.getMessage());
return "默认值";
}
return result;
});
- exceptionally(Function<Throwable, ? extends T> fn):处理异常并提供默认值
- handle(BiFunction<? super T, Throwable, ? extends U> fn):处理正常和异常情况
组合多个 CompletableFuture
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
// 使用 thenCombine 组合两个 CompletableFuture 的结果
CompletableFuture<String> combinedFuture = future1.thenCombine(future2,
(result1, result2) -> result1 + " " + result2);
// 使用 thenCompose 进行链式异步调用
CompletableFuture<String> composedFuture = future1.thenCompose(result ->
CompletableFuture.supplyAsync(() -> result + " World"));
- thenCompose(Function<? super T,? extends CompletionStage<U>> fn):链式调用
- thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):组合两个 CompletableFuture
并行执行多个任务
// 使用 allOf 等待所有任务完成
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "任务1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "任务2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "任务3");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
// 等待所有任务完成
allFutures.join();
// 使用 anyOf 等待任一任务完成
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2, future3);
Object result = anyFuture.join();
- allOf(CompletableFuture<?>... cfs):等待所有 CompletableFuture 完成
- anyOf(CompletableFuture<?>... cfs):等待任一 CompletableFuture 完成
CompletableFuture封装类
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 异步批量处理器工具类 用于处理批量异步任务,提高处理效率
*
* @author hudy
* @since 1.0
*/
public class AsyncBatchProcessor {
/**
* 异步处理批量任务(使用自定义线程池)
*
* @param items 待处理的元素列表
* @param processor 元素处理器
* @param executor 自定义线程池
* @param <T> 元素类型
*/
public static <T> void processAsync(List<T> items, Consumer<T> processor, Executor executor) {
if (items == null || items.isEmpty()) {
return;
}
// 创建异步任务列表,使用指定的线程池
List<CompletableFuture<Void>> futures = items.stream()
.map(item -> CompletableFuture.runAsync(() -> processor.accept(item), executor))
.collect(Collectors.toList());
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
/**
* 异步处理批量任务并返回结果(使用自定义线程池)
*
* @param items 待处理的元素列表
* @param processor 元素处理器
* @param executor 自定义线程池
* @param <T> 元素类型
* @param <R> 结果类型
* @return 处理结果列表
*/
public static <T, R> List<R> processAsyncWithResultList(List<T> items, Function<T, R> processor,
Executor executor) {
if (items == null || items.isEmpty()) {
return Collections.emptyList();
}
// 创建异步任务列表,使用指定的线程池
List<CompletableFuture<R>> futures = items.stream()
.map(item -> CompletableFuture.supplyAsync(() -> processor.apply(item), executor))
.collect(Collectors.toList());
// 等待所有任务完成并收集结果
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0]));
// 返回所有处理结果
return allFutures.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList())).join();
}
/**
* 异步处理批量任务(带线程安全结果收集,使用自定义线程池)
*
* @param items 待处理的元素列表
* @param processor 元素处理器
* @param resultCollector 结果收集器
* @param executor 自定义线程池
* @param <T> 元素类型
* @param <R> 结果类型
*/
public static <T, R> void processAsyncWithResult(List<T> items,
ItemProcessor<T, R> processor,
ResultCollector<R> resultCollector,
Executor executor) {
if (items == null || items.isEmpty()) {
return;
}
// 创建异步任务列表,使用指定的线程池
List<CompletableFuture<Void>> futures = items.stream()
.map(item -> CompletableFuture.runAsync(() -> {
R result = processor.process(item);
if (result != null && resultCollector != null) {
synchronized (resultCollector) {
resultCollector.collect(result);
}
}
}, executor))
.collect(Collectors.toList());
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
/**
* 异步处理批量任务并返回CompletableFuture列表(使用自定义线程池)
*
* @param items 待处理的元素列表
* @param processor 元素处理器
* @param executor 自定义线程池
* @param <T> 元素类型
* @param <R> 结果类型
* @return CompletableFuture结果列表
*/
public static <T, R> List<CompletableFuture<R>> processAsyncFutureList(List<T> items,
Function<T, R> processor, Executor executor) {
if (items == null || items.isEmpty()) {
return Collections.emptyList();
}
// 创建异步任务列表,使用指定的线程池
return items.stream()
.map(item -> CompletableFuture.supplyAsync(() -> processor.apply(item), executor))
.collect(Collectors.toList());
}
/**
* 元素处理器接口
*
* @param <T> 输入元素类型
* @param <R> 处理结果类型
*/
@FunctionalInterface
public interface ItemProcessor<T, R> {
/**
* 处理单个元素
*
* @param item 待处理元素
* @return 处理结果
*/
R process(T item);
}
/**
* 结果收集器接口
*
* @param <R> 结果类型
*/
@FunctionalInterface
public interface ResultCollector<R> {
/**
* 收集处理结果
*
* @param result 处理结果
*/
void collect(R result);
}
}
自定义线程池
创建配置类
提供了四种不同类型的线程池,以满足不同业务场景的需求
package net.icsoc.ark.common.aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 自定义线程池配置类 提供多种类型的线程池以满足不同业务场景需求
*/
@Configuration
public class ThreadPoolConfig {
/**
* IO密集型任务线程池 适用于文件读写、网络请求等IO密集型操作
*/
@Bean("ioTaskExecutor")
public ThreadPoolTaskExecutor ioTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(20);
// 最大线程数
executor.setMaxPoolSize(100);
// 队列容量
executor.setQueueCapacity(200);
// 线程空闲时间
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("IO-Task-");
// 拒绝策略:由调用线程处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时长
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
return executor;
}
/**
* CPU密集型任务线程池 适用于计算密集型任务,如数据处理、复杂算法等
*/
@Bean("cpuTaskExecutor")
public ThreadPoolTaskExecutor cpuTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数,通常设置为CPU核心数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 最大线程数
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// 队列容量
executor.setQueueCapacity(100);
// 线程空闲时间
executor.setKeepAliveSeconds(30);
// 线程名称前缀
executor.setThreadNamePrefix("CPU-Task-");
// 拒绝策略:由调用线程处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时长
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
return executor;
}
/**
* 高并发任务线程池 适用于需要处理大量并发请求的场景
*/
@Bean("highConcurrentExecutor")
public ThreadPoolTaskExecutor highConcurrentExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(50);
// 最大线程数
executor.setMaxPoolSize(200);
// 队列容量
executor.setQueueCapacity(1000);
// 线程空闲时间
executor.setKeepAliveSeconds(300);
// 线程名称前缀
executor.setThreadNamePrefix("High-Concurrent-");
// 拒绝策略:由调用线程处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时长
executor.setAwaitTerminationSeconds(120);
// 初始化
executor.initialize();
return executor;
}
/**
* 定时任务线程池 适用于执行定时任务或延迟任务
*/
@Bean("scheduledTaskExecutor")
public ThreadPoolTaskExecutor scheduledTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(10);
// 最大线程数
executor.setMaxPoolSize(50);
// 队列容量
executor.setQueueCapacity(500);
// 线程空闲时间
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("Scheduled-Task-");
// 拒绝策略:由调用线程处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时长
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
return executor;
}
}
ThreadPoolExecutor ScheduledThreadPoolExecutor使用场景
ThreadPoolExecutor适用于:
- 需要并发处理大量独立任务
- 对线程池有精细控制需求
- 需要自定义拒绝策略、线程工厂等
ScheduledThreadPoolExecutor适用于:
- 需要延迟执行任务
- 需要周期性执行任务(如定时检查、轮询等)
- 需要替代Timer类的功能(Timer只支持单线程)
使用场景
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
// 调度任务,每个任务间隔一定时间执行
Future<String> futureResult = scheduler.schedule(() -> {
// 任务内容
}, (long) i * grpcDelay, TimeUnit.MILLISECONDS);
这种方式可以控制任务的执行时间,实现批量任务的间隔执行,避免系统过载。
异步自定义线程池结合
ForkJoinPool.commonPool() 是CompletableFuture默认使用的线程池。避免使用默认的 ForkJoinPool,防止任务之间相互影响。CompletableFuture 和 ExecutorService 紧密配合,实现了高效的异步并发处理。这种组合使用方式是 Java 异步编程的最佳实践之一,既保证了性能,又提供了良好的可控性和可维护性。
两者协同工作流程
- 任务提交:使用 CompletableFuture.supplyAsync() 将任务提交给 ExecutorService
- 并行执行:ExecutorService 管理线程池,将任务分配给可用线程执行
- 结果处理:CompletableFuture 提供链式调用和组合操作来处理异步结果
- 资源管理:使用完成后关闭 ExecutorService
使用场景
- 1. 微服务并行调用
同时调用多个独立的微服务接口,然后聚合返回结果,提升接口响应速度。
- 2. 数据报表生成
从多个数据源并行获取统计数据,最后组合生成完整的业务报表。
- 3. 缓存预热
应用启动时并行加载多个缓存数据,缩短系统预热时间。
- 4. 批量数据处理
将大量数据分批并行处理,提高数据处理效率。
- 5. 异步事件处理
用户注册后并行发送邮件通知、短信提醒、记录日志等操作。
- 6. API网关响应聚合
API网关同时调用多个后端服务,聚合响应后统一返回给客户端。
- 7. 文件上传处理
大文件分块并行上传和处理,提升文件处理速度。
- 8. 实时数据管道
构建异步数据处理流水线,实现数据的验证、转换、丰富和存储。
- 9. 第三方接口调用
调用多个第三方API接口并设置超时控制,避免阻塞主线程。
- 10. 复杂业务流程
将复杂的业务流程拆分为多个并行或串行的异步任务执行。
示例说明
该示例模拟了多个任务的异步执行,并通过 CompletableFuture 和 ExecutorService 来实现并发处理。每个任务会休眠一段时间(模拟耗时操作),然后返回结果。
// 创建自定义线程池
ExecutorService customExecutor = Executors.newFixedThreadPool(5);
try {
// 测试使用自定义线程池的processAsync方法
System.out.println("=== 测试使用自定义线程池的processAsync方法 ===");
List<String> items = Arrays.asList("item1", "item2", "item3", "item4", "item5");
AsyncBatchProcessor.processAsync(items, item -> {
// 模拟处理
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("使用自定义线程池处理完成: " + item + ",线程:" + Thread.currentThread().getName());
}, customExecutor);
// 测试使用自定义线程池的processAsyncWithResultList方法
System.out.println("\n=== 测试使用自定义线程池的processAsyncWithResultList方法 ===");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> results = AsyncBatchProcessor.processAsyncWithResultList(numbers, num -> {
// 模拟处理
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("处理数字: " + num + ",线程:" + Thread.currentThread().getName());
return num * num; // 返回平方值
}, customExecutor);
System.out.println("处理结果: " + results);
// 测试使用自定义线程池的processAsyncFutureList方法
System.out.println("\n=== 测试使用自定义线程池的processAsyncFutureList方法 ===");
List<CompletableFuture<String>> futures = AsyncBatchProcessor.processAsyncFutureList(items, item -> {
// 模拟处理
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Processed: " + item + " by " + Thread.currentThread().getName();
}, customExecutor);
// 等待所有任务完成并收集结果
List<String> futureResults = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println("Future处理结果: " + futureResults);
} finally {
// 关闭线程池
customExecutor.shutdown();
}
批量入库
@Autowired
@Qualifier("scheduledTaskExecutor")
private ExecutorService fixedExecutorService;
/**
* 异步批量写入数据
*
* @param hotelList
* @param billMonth
*/
public void asyncBatchAddBillMonthlyData(List<BillAccountInfo> hotelList, String billMonth) {
List<CompletableFuture<Void>> futures = hotelList.stream()
.map(info -> CompletableFuture.runAsync(() -> {
try {
BillMonthly entity = new BillMonthly();
entity.setHotelId(info.getHotelId());
entity.setBillMonth(billMonth);
billMonthlyService.save(entity);
} catch (Exception e) {
log.error("异步写入BillMonthly失败,hotelId: {}, 错误信息: {}", info.getHotelId(), e.getMessage(),
e);
}
}, fixedExecutorService))
.collect(Collectors.toList());
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 不需要手动关闭线程池,由Spring容器管理
}
批量处理限制
控制并发数量,避免系统资源(特别是数据库连接)被耗尽。
// 限制并发数,避免数据库连接池耗尽
final int maxConcurrency = 10;
List<List<Phones>> batches = new ArrayList<>();
// 将trunkList分批处理
for (int i = 0; i < trunkList.size(); i += maxConcurrency) {
batches.add(trunkList.subList(i, Math.min(i + maxConcurrency, trunkList.size())));
}
// 分批执行删除操作
batches.forEach(batch -> {
AsyncBatchProcessor.processAsync(batch, item -> {
});
});
每一批都是临时创建的独立任务集合,当前一批处理完成后,其对应的 CompletableFuture 列表就超出作用域,被垃圾回收
解决线程安全问题
为了解决CompletableFuture的线程安全问题,可以采取以下措施:
- 避免共享变量:在多个任务之间尽量避免共享变量,使用局部变量或者将变量作为方法参数传递。
- 使用线程安全的数据结构:如果必须共享变量,可以使用线程安全的数据结构,例如AtomicInteger代替int。
- 使用同步机制:可以使用synchronized关键字或者Lock接口来保证多个任务的互斥访问。
- 使用线程安全的 CopyOnWriteArrayList 替代普通的 ArrayList,类似的ConcurrentHashMap等
例子
// 使用线程安全的集合替代普通ArrayList
CopyOnWriteArrayList<String> mixedNums = new CopyOnWriteArrayList<>();
// 使用线程安全的ConcurrentHashMap替代HashMap
ConcurrentHashMap<String,String> listGz = new ConcurrentHashMap<>();
// 使用CompletableFuture并发处理每个号码的删除操作
List<CompletableFuture<Void>> futures = phones.stream()
.map(phone -> CompletableFuture.runAsync(() -> {
listGz.put(phone, trunkDeleteDto.getVccCode());
ccPhoneMapper.deleteByPhone(phone);
// 查询下线中继号关联其他中继号混显规则的号码
List<String> relationPhone = ccPhoneMapper.getRelationPhone(phone);
if (CollectionUtils.isNotEmpty(relationPhone)) {
mixedNums.addAll(relationPhone);
}
}, executorService))
.collect(Collectors.toList());
// 等待所有异步任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
317

被折叠的 条评论
为什么被折叠?



