使用Future可以获得异步执行结果
Future<String> future = executor.submit(task);
String result = future.get();
但是当我们使用get()获得异步执行结果的时候,这个方法可能会阻塞。我们通过while循环反复调用isDone()来判断异步结果是否已经完成。
while(!future.isDone()){
Thread.sleep(1);
}
String result = future.get()
所以使用Future获得异步执行的结果有2个方法:
- 1.调用阻塞方法get()
- 2.轮询isDone()
这2种方法都不是很好,我们期望在异步任务完成的时候自动返回结果,所以JDK提供了CompletableFuture接口。
CompletableFutrue接口
当我们使用CompletableFuture接口时,任务执行结束的时候,它会自动调用我们设置好的回调函数;当任务发生异常的时候,它也可以自动调用我们设置好的另一个回调函数。
CompletableFuture<String> cf = getCompletableFutureFromSomewhere();
cf.thenAccept(new Consumer<String>(){ //thenAccept传入一个回调对象,就可以获得正常运行的异步结果
public void accept(String result){
System.out.println("正常运行获得异步结果:"+ result);
}
});
cf.exceptionally(new Function<Throwable, String>(){ //用exceptionally传入一个回调对象,可以获得运行时发生异常的情况
public String apply(Throwable, String){
System.out.println("运行发生异常:"+ t.getMessage());
return null;
}
});
使用Java8新增的函数式语法可以进一步简化代码
CompletableFuture<String> cf = getCompletableFutureFromSomewhere();
cf.thenAccept( (result) -> {
System.out.println("正常运行获得异步结果");
});
cf.exceptionally( (t) -> {
System.out.println("运行时发生异常:" + t.getMessage());
return null;
});
CompletableFuture的优点:
- 异步任务结束时,会自动回调某个对象的方法
- 异步任务出错时,会自动回调某个对象的方法
- 主线程设置好回调后,不再关心异步任务的执行
CompletableFuture的基本用法:
CompletableFuture<String> cf = CompletableFuture.supplyAsync("异步执行实例");
cf.thenAccept("获得结果后的操作");
cf.exceptionally("发生异常时的操作");
代码1:
DownloadUtil.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class DownloadUtil implements Callable<String> {
String url;
public DownloadUtil(String url){
this.url = url;
}
public String call() throws Exception {
URLConnection conn = new URL(this.url).openConnection();
conn.connect();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))){//有问题
String s = null;
StringBuilder sb = new StringBuilder();
while ((s = reader.readLine()) != null) {
sb.append(s).append("\n");
}
return sb.toString();
}
}
static String download(String url) throws Exception{
ExecutorService executor = Executors.newCachedThreadPool();
DownloadUtil task= new DownloadUtil(url);
Future<String> future = executor.submit(task);
String html = future.get();
executor.shutdown();
return html;
}
}
CompletableFutureSample.java
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
class StockSupplier implements Supplier<Float>{
public Float get(){
String url = "http://hq.sinajs.cn/list=sh000001";
System.out.println("GET: "+url);
try{
String result = DownloadUtil.download(url);
String[] ss = result.split(",");
return Float.parseFloat(ss[3]);
}catch (Exception e){
throw new RuntimeException();
}
}
}
public class CompletableFutureSample {
public static void main(String[] args) throws Exception{
CompletableFuture<Float> getStockFuture = CompletableFuture.supplyAsync(new StockSupplier());
getStockFuture.thenAccept(new Consumer<Float>() {
@Override
public void accept(Float price) {
System.out.println("Current price:" + price);
}
});
getStockFuture.exceptionally(new Function<Throwable, Float>() {
@Override
public Float apply(Throwable t) {
System.out.println("Error: " + t.getMessage());
return null;
}
});
getStockFuture.join();
}
}
多个CompletableFuture可以串行执行
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync("异步执行实例1");
CompletableFuture<LocalDate> cf2 = cf1.thenAcceptAsync("异步执行实例2");
CompletableFuture<Float> cf3 = cf2.thenApplyAsync("异步执行实例3");
cf3.thenAccept("实例3获得结果后的操作");
import java.awt.geom.FlatteningPathIterator;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
class Price{
final String code;
final float price;
public Price(String code,float price){
this.code = code;
this.price = price;
}
}
class StockLookupSupplier implements Supplier<String>{
String name;
public StockLookupSupplier(String name){
this.name = name;
}
public String get(){
System.out.println("lookup:"+name);
try{
String url = "http://suggest3.sinajs.cn/suggest/type=11,12&key=0&name="+name;
String result = DownloadUtil.download(url);
String[] ss = result.split(",");
return ss[3];
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
public class CompletableFutureSequenceSample {
public static void main(String[] args) {
String name = "上证指数";
CompletableFuture<String> getStockCodeFuture = CompletableFuture.supplyAsync(new StockLookupSupplier(name));
CompletableFuture<Price> getStockPriceFuture = getStockCodeFuture.thenApplyAsync(new Function<String, Price>() {
@Override
public Price apply(String code) {
System.out.println("get Code:"+code);
try{
String url = "http://hq.sinajs.cn/list="+code;
String result = DownloadUtil.download(url);
String[] ss = result.split(",");
return new Price(code, Float.parseFloat(ss[3]));
}catch (Exception e){
throw new RuntimeException(e);
}
}
});
getStockPriceFuture.thenAccept(new Consumer<Price>() {
@Override
public void accept(Price price) {
System.out.println(price.code+":"+price.price);
}
});
getStockPriceFuture.join();
}
}
多个CompletableFuture可以并行执行
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
class StockPrice{
final String from;
final float price;
StockPrice(float price,String from){
this.from = from;
this.price = price;
}
public String toString(){
return "Price:"+price+" from "+from;
}
}
class StockFromSina implements Supplier<StockPrice>{
public StockPrice get(){
String url = "http://hq.sinajs.cn/list=sh000001";
System.out.println("GET:"+url);
try{
String result = DownloadUtil.download(url);
String[] ss = result.split(",");
return new StockPrice(Float.parseFloat(ss[3]),"sina");
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
class StockFromNetease implements Supplier<StockPrice>{
public StockPrice get(){
String url = "http://api.money.126.net/data/feed/0000001,money.api?callback=_ntes_quote_callback";
System.out.println("GET:"+url);
try{
String result = DownloadUtil.download(url);
int priceIndex = result.indexOf("\"price\"");
int start = result.indexOf(":",priceIndex) + 1;
int end = result.indexOf(",",priceIndex);
System.out.println(Float.parseFloat(result.substring(start,end)));
return new StockPrice(Float.parseFloat(result.substring(start,end)),"netease");
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
public class CompletableFutureAnyOfSample {
public static void main(String[] args) throws Exception{
CompletableFuture<StockPrice> getSockFromSina = CompletableFuture.supplyAsync(new StockFromSina());
CompletableFuture<StockPrice> getStockFromNetease = CompletableFuture.supplyAsync(new StockFromNetease());
CompletableFuture<Object> getStock = CompletableFuture.anyOf(getSockFromSina,getStockFromNetease);
getStock.thenAccept(new Consumer<Object>() {
public void accept(Object result){
System.out.println("Result:"+result);
}
});
getStock.join();
}
}
CompletableFuture的命名规则:
- xxx():继续在已有的线程中执行
- xxxAsync():用Executor的新线程执行
总结:
CompletableFuture对象可以指定异步处理流程:
- thenAccept()处理正常结果
- exceptional()处理异常结果
- thenApplyAsync()用于串行化另一个CompletableFuture
- anyOf/allOf用于并行化两个CompletableFuture