【CompletableFuture java8 使用场景一】

需求

有一个业务场景如下:对外提供一个查询接口,该接口接收一个指定的超时时间参数 timeout,接口并发执行两个方法,方法一为查询缓存,方法二为http接口查询,http接口的超时时间为timeout。如果在timeout时间内方法二有返回结果,则接口返回方法二的查询结果。如果方法二在指定的超时内没有返回结果,则查询接口返回方法一的执行结果。同时如果方法二如果超时了,需要异步等待300ms,尽可能获取方法二的执行结果,如果有结果就写一条日志,否则丢弃中断http请求。

需求分析

  1. 接口接收超时参数: 接口定义一个timeout参数。
  2. 并发执行查询: 同时执行查询缓存(cacheQuery)和HTTP接口查询(httpQuery)。
  3. 优先返回HTTP查询结果: 如果在timeout时间内httpQuery有结果,返回该结果。
  4. 超时返回缓存结果: 如果httpQuery超时,返回cacheQuery结果。
  5. 记录日志: 如果httpQuery超时,异步等待300ms,记录结果或中断请求。

技术实现

Future 实现方式

Controller

java 复制代码
@RestController
public class QueryController {

    @Autowired
    private QueryService queryService;

    @RequestMapping(value = "/query", method = RequestMethod.GET)
    public ResponseEntity<?> query(@RequestParam("timeout") long timeout) {
        try {
            String result = queryService.queryWithTimeout(timeout);
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }
}

Service

java 复制代码
@Service
public class QueryService {

    @Autowired
    private CacheQueryComponent cacheQueryComponent;

    @Autowired
    private HttpQueryComponent httpQueryComponent;

    public String queryWithTimeout(long timeout) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        try {
            // 提交缓存查询任务
            Future<String> cacheFuture = executor.submit(() -> cacheQueryComponent.query());

            // 提交HTTP查询任务,带有超时设置
            Future<String> httpFuture = executor.submit(() -> httpQueryComponent.query(timeout));

            try {
                // 优先获取HTTP查询结果
                return httpFuture.get(timeout, TimeUnit.MILLISECONDS);
            } catch (TimeoutException e) {
                // HTTP查询超时,返回缓存查询结果
                return cacheFuture.get();
            } finally {
                // 如果HTTP查询超时,异步等待300ms
                if (!httpFuture.isDone()) {
                    executor.submit(() -> {
                        try {
                            String result = httpFuture.get(300, TimeUnit.MILLISECONDS);
                            // 记录日志
                            logResult(result);
                        } catch (Exception ex) {
                            httpFuture.cancel(true); // 中断HTTP请求
                        }
                    });
                }
            }
        } finally {
            executor.shutdown();
        }
    }

    private void logResult(String result) {
        // 日志记录逻辑
        System.out.println("Delayed HTTP query result: " + result);
    }
} 

缓存查询组件

java 复制代码
@Component
public class CacheQueryComponent {
    public String query() {
        try {
	      Thread.sleep(20);
	    } catch (InterruptedException e) {
	      throw new RuntimeException(e);
	    }
	    printLog("cache result");
	    return "cache result";
    }
} 

HTTP查询组件

java 复制代码
@Component
public class HttpQueryComponent {
    public String query() {
        try {
	      Thread.sleep(400);
	    } catch (InterruptedException e) {
	      throw new RuntimeException(e);
	    }
	    printLog("cache result");
	    return "cache result";
    }
} 

CompletableFuture 实现

Service

java 复制代码
@Service
public class QueryService {

    @Autowired
    private CacheQueryComponent cacheQueryComponent;

    @Autowired
    private HttpQueryComponent httpQueryComponent;

    public String queryWithTimeout(long timeout) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        try {
            // 创建一个异步任务,从缓存中查询数据
		    CompletableFuture<String> cacheTask = CompletableFuture.supplyAsync(() -> {
		      printLog("queryFromCache");
		      return cacheQueryComponent.query();
		    });
		
		    // 创建一个异步任务,从HTTP中查询数据
		    CompletableFuture<String> httpTask = CompletableFuture.supplyAsync(() -> {
		      printLog("queryFromHttp");
		      return httpQueryComponent.query();
		    });
		
		    // 如果HTTP任务在200ms内没有完成,就取消任务
		    executor.schedule(() -> {
		      if (!httpTask.isDone()) {
		        try {
		          String httpResult = httpTask.get(300, TimeUnit.MILLISECONDS);
		          printLog("HTTP task completed after 200ms: " + httpResult);
		        } catch (Exception e) {
		          printLog("HTTP task cancel");
		          httpTask.cancel(true);
		        }
		      }
		    }, 200, TimeUnit.MILLISECONDS);
		
		    // 创建一个延迟200ms的任务
		    CompletableFuture<Void> delay = CompletableFuture.runAsync(() -> {
		      try {
		        Thread.sleep(200);
		      } catch (InterruptedException e) {
		        throw new RuntimeException(e);
		      }
		    });
		
		    // 如果HTTP任务完成,就返回HTTP任务的结果,否则返回缓存任务的结果
		    return delay.thenApply(v -> {
		      if (httpTask.isDone()) {
		        return httpTask.join();
		      } else {
		        return cacheTask.join();
		      }
		    }).join();
        } finally {
            executor.shutdown();
        }
    }

    private void logResult(String result) {
        // 日志记录逻辑
        System.out.println("Delayed HTTP query result: " + result);
    }
} 
相关推荐
hycccccch几秒前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
天天向上杰1 小时前
面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
java·bigdecimal
请来次降维打击!!!1 小时前
优选算法系列(5.位运算)
java·前端·c++·算法
用键盘当武器的秋刀鱼1 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
嘤国大力士2 小时前
C++11&QT复习 (七)
java·c++·qt
松树戈2 小时前
Java常用异步方式总结
java·开发语言
weisian1512 小时前
Java常用工具算法-3--加密算法2--非对称加密算法(RSA常用,ECC,DSA)
java·开发语言·算法
小李同学_LHY2 小时前
三.微服务架构中的精妙设计:服务注册/服务发现-Eureka
java·spring boot·spring·springcloud
非ban必选3 小时前
spring-ai-alibaba第四章阿里dashscope集成百度翻译tool
java·人工智能·spring
非ban必选3 小时前
spring-ai-alibaba第五章阿里dashscope集成mcp远程天气查询tools
java·后端·spring