【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);
    }
} 
相关推荐
xcl09251 小时前
幼儿托育系统开发实战:从需求分析到上线全流程指南
java·大数据·需求分析
吴声子夜歌1 小时前
ApacheCommons——commons-cli(命令行参数解析)
java·开发语言·apache
小小猪的春天2 小时前
Java 手写第一个 MCP Server:Spring AI MCP 半小时跑通
java·人工智能·spring boot·ai编程
find1star2 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
今天AI了吗2 小时前
DeepSeek Harness 深度解析:从评测架构到实战落地
java·网络·数据库·人工智能·架构·java-ee
许彰午3 小时前
27-AuthService登录链路
java·低代码·架构
泡海椒3 小时前
JQuick-Curl 性能分析:并发场景下的性能表现与调优,第三方接口调用不只要快写也要稳跑
java·开发语言·okhttp
Rain的Java大神之路4 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
自动化监测Learner4 小时前
Navicat Premium 17 中文版安装教程(2026最新版)
java·linux·数据库
那个松鼠很眼熟w4 小时前
4.Spring-Ai入门案例
java·人工智能·spring