廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture

使用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();
    }
}

1418970-20190616231021031-256232547.jpg

多个CompletableFuture可以串行执行

    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync("异步执行实例1");
    CompletableFuture<LocalDate> cf2 = cf1.thenAcceptAsync("异步执行实例2");
    CompletableFuture<Float> cf3 = cf2.thenApplyAsync("异步执行实例3");
    cf3.thenAccept("实例3获得结果后的操作");

1418970-20190616231613374-1268100634.png

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();
    }
}

1418970-20190617003053538-1843024867.png

多个CompletableFuture可以并行执行

1418970-20190617003220178-790877813.png

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();
    }
}

1418970-20190617212329223-399055898.png
1418970-20190617212525486-403553464.png

CompletableFuture的命名规则:

  • xxx():继续在已有的线程中执行
  • xxxAsync():用Executor的新线程执行

总结:

CompletableFuture对象可以指定异步处理流程:

  • thenAccept()处理正常结果
  • exceptional()处理异常结果
  • thenApplyAsync()用于串行化另一个CompletableFuture
  • anyOf/allOf用于并行化两个CompletableFuture

转载于:https://www.cnblogs.com/csj2018/p/11031781.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值