文章目录
Future简介
什么是Future?
Future是一个接口,用来返回异步的结果。它表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,此方法在计算完成前可以被阻塞。
Future的使用场景
Future通常被使用在需要多个线程协作计算的情形中。
Future接口内部的常用方法
1> cancel,取消Callable的执行,当Callable还没有完成时
2> get,获得Callable的返回值
3> isCanceled,判断是否取消了
4> isDone,判断是否完成
Future的常见用法
一、基础用法:
重写Callable接口的call方法,放到异步线程的.submit方法中执行。
可以直接重写call方法;
也可以定义一个类继承Callable接口,在类中重写call方法.
代码实例:
package future.com;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class TaskWithResult implements Callable<String>{
public String call() throws Exception {
// TODO Auto-generated method stub
Thread.sleep(1000);
return "OK";
}
}
public class CallableDemo {
public static void main(String[] args) throws Exception {
/**
* 一、直接重写call方法,然后在.submit方法中传入call
* */
// 开启线程池
final ExecutorService exec = Executors.newFixedThreadPool(3);
// 直接重写Callable的call方法
Callable<String> call = new Callable<String>() {
public String call() throws Exception {
return "Other less important but longtime things.";
}
};
Future<String> task = exec.submit(call);
/**
* Future线程类的常用方法
* */
// 获取Callable返回值
System.out.println(task.get());
// 判断是否执行完成
System.out.println(task.isDone());
//当Callable没执行完成时,取消Callable的执行
System.out.println(task.cancel(false));
// 判断是否被取消
System.out.println(task.isCancelled());
/**
* 二、TaskWithResult类继承Callable接口,在类里面重写call方法,.submit方法中传入TaskWithResult类
* */
Future<String> st=exec.submit(new TaskWithResult());
System.out.println(st.get());
// 关闭线程
exec.shutdown();
}
}
二、进阶用法:
定义返回值类型为进程类的方法,异步调用,阻塞等待。再对结果集进行处理
假定一个场景:
要循环调访问某些接口,并处理得到的数据。
具体实现:
1)service层定义一个返回值为进程类的请求方法,在该方法中请求数据并返回结果
package com.service;
package com.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.endtity.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.concurrent.Future;
@Service
public class JsonService {
@Autowired
private RestTemplate restTemplate;
private ObjectMapper objectMapper = new ObjectMapper();
@Async
public Future<JsonResult> query(String url, Object param){
JsonResult result = null;
try {
String json = restTemplate.postForObject(url, param, String.class);
result = objectMapper.readValue(json, new TypeReference<JsonResult>(){});
} catch (IOException e) {
} finally {
}
return new AsyncResult<>(result);
}
}
2)定义返回结果
com.endtity.JsonResult
package com.endtity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class JsonResult {
@JsonProperty("code")
private String code;
@JsonProperty("msg")
private String msg;
@JsonProperty("result")
private Object result;
}
3)Controll层的实现
1> 异步调用取数据service的方法;
2> 阻塞等待,用isDone方法判断是否执行完成;
3> 合并结果集;
4> 按照自己的需求处理结果集,并返回处理后的结果
package com.api;
package com.api;
import com.endtity.JsonResult;
import com.service.JsonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
@RequestMapping("/rest/api/track")
@CrossOrigin("*")
public class JsonControl {
private Logger logger = LoggerFactory.getLogger(JsonControl.class);
@Autowired
private JsonService jsonservice;
public static void main(String[] args) {
SpringApplication.run(JsonControl.class, args);
}
@PostMapping("test")
public List<JsonResult> test(@RequestBody Object json) throws InterruptedException, ExecutionException {
// 配置要循环访问的接口地址
List<String> ls = new ArrayList();
ls.add("https://");
ls.add("https://");
List<JsonResult> result = null;
Map<String, Future<JsonResult>> obj = new HashMap<>();
// 异步调用
for(int i=0; i<ls.size(); i++){
Future<JsonResult> ss=jsonservice.query(ls.get(i), json);
obj.put(i+"", ss);
}
// 阻塞等待
while(true){
boolean bool=true;
for(int i=0;i<3;i++){
if(bool&&obj.get(i+"").isDone()){
bool=true;
}else{
bool=false;
}
}
if(bool){
break;
}
}
// 合并结果集
for(int i=0; i<ls.size(); i++){
JsonResult o = obj.get(i+"").get();
result.add(o);
}
// 对结果集进行聚合
// 返回结果集
return result;
}
}
一些实现细节:
1)在写service层的进程类方法是,虽然进程执行完后丢给我们的是一个 JsonResult 的结果对象。但是在进程类中不能直接 return 一个 JsonResult 对象,而是应该 new 一个 异步进程结果AsyncResult<>()将方法的执行结果传出。
2)control层有一个 while 死循环,必须通过isDone()方法判断进程全部执行完后才能对结果集进行处理。
3)记得处理一些相关的异常