CompletableFuture

但是但我们使用get()方法获取异步执行的结果的时候,方法可能会阻塞

我们要通过isDone()判断异步执行结果是否已经完成
使用Future获得异步执行的结果有两个方法:

1. 阻塞的方法: get()

2 轮询: isDone()

都不是很好,我们期望在异步任务执行完毕的时候,我们能自动获得结果.
所以JDK提供了CompletableFuture接口:

任务结束的时候会自动调用回调函数,当发生异常的时候,会调用另一个回调函数.

当异步执行结果执行完毕的时候,我们用.thenAccept()就会正常运行获得异步结果.

我们用exceptionally可以获得异常运行时候的结果
CompletableFuture的优点:

1. 异步任务结束的时候,会自动回调某个对象的方法

2. 异步任务出错的时候,会自动回调某个对象的方法

3. 主线程设置好回调后,不再关心异步任务的执行
CompletableFuture的用法:

我们用thenAccept()来获得一个结果的操作,我们用exceptionally()来获取操作异常时候的操作
package com.leon.day05;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

class DownloadUtil {
	public static String download(String url) throws IOException{
		HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); 
		conn.setDoOutput(false);
		conn.setAllowUserInteraction(false);
		conn.setConnectTimeout(3000);
		conn.setReadTimeout(3000);
		conn.connect();
		ByteArrayOutputStream output = new ByteArrayOutputStream(10240);
		try(InputStream input = conn.getInputStream()){
			int n;
			byte[] buffer = new byte[2048];
			while((n = input.read(buffer)) != -1){
				output.write(buffer, 0, n);
			}
		}
		conn.disconnect();
		return new String(output.toByteArray(), "UTF-8");
	}
}
class StockSupplier implements Supplier<Float>{
	@Override
	public Float get(){
		// 我们传入一个URL,获取股票的价格
		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(e);
		}
	}
}
public class CompletableFutureSample{
	public static void main(String[] args) throws Exception{
		// 传入任务,创建一个CompeltableFuture的实例
		CompletableFuture<Float> getStockFuture = CompletableFuture.supplyAsync(new StockSupplier());
		// 然后通过实例调用thenAccept(),在异步结果正常的情况下打印出股票的价格
		getStockFuture.thenAccept(new Consumer<Float>() {
			@Override
			public void accept(Float price){
				System.out.println("Current price: " + price);
			}
		});
		// 调用exceptionally在异步结果出错的时候打印一个error
		getStockFuture.exceptionally(new Function<Throwable, Float>() {
			@Override
			public Float apply(Throwable t){
				System.out.println("Error: " + t.getMessage());
				return Float.NaN;
			}
		});
		getStockFuture.join();
	}
}
多个CompletableFuture可以串行执行:

我们可以先通过异步任务查询证券代码,然后通过查询到的证券代码再启动一个异步任务,最后我们显示一个

证券的价格

package com.leon.day05;

import java.net.URLEncoder;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

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=" + URLEncoder.encode(name, "UTF-8");
			String result = DownloadUtil.download(url);
			String[] ss = result.split(",");
			return ss[3];
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
}


public class CompletableFutureSequenceSample {
	/**
	 * 两个CompletableFuture串行执行
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception{
		String name = "上证指数";
		// 通过证券名称获取证券代码
		// 首先我们查询了上证指数的代码,得到了证券代码
		CompletableFuture<String> getStockCodeFuture = CompletableFuture.supplyAsync(new StockLookupSupplier(name));
		// 当获得证券代码后再获得证券价格
		// 然后我们根据证券代码查询证券的价格
		CompletableFuture<Price> getStockPriceFuture = getStockCodeFuture.thenApplyAsync(new Function<String, Price>() {
			public Price apply(String code){
				System.out.println("got 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);
				}
			}
		});
		// 调用thenAccept打印最后一个结果
		getStockPriceFuture.thenAccept(new Consumer<Price>() {
			public void accept(Price p){
				System.out.println(p.code + ":" + p.price);
			}
		});
		getStockPriceFuture.join();
	}
}

我们可以从新浪查询证券价格,也可以从网易查询证券价格.

这两个异步操作可以异步执行,我们可以设置anyof任意一个异步任务
package com.leon.day05;

import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;

class StockPrice{
	final float price;
	final String from;
	public StockPrice(float price, String from) {
		this.price = price;
		this.from = from;
	}
	public String toString(){
		return "Price: " + price + " from " + from;
	}
}

/**
 * 从新浪获取证券的价格
 * @author Leon.Sun
 *
 */
class StockFromSina implements Supplier<StockPrice>{
	@Override
	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);
		}
	}
}

/**
 * 从网易获取证券的价格
 * @author Leon.Sun
 *
 */
class StockFromNetease implements Supplier<StockPrice>{
	@Override
	public StockPrice get(){
		String url = "http://api.money.126.net/data/feed/0000001,money.api";
		System.out.println("GET: " + url);
		try{
			String result = DownloadUtil.download(url);
			int priceIndex = result.indexOf("\"price\"");
			int start = result.indexOf(":", priceIndex);
			int end = result.indexOf(",", priceIndex);
			return new StockPrice(Float.parseFloat(result.substring(start+1, end)), "netease");
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
}
public class CompletableFutureAnyOfSample {
	public static void main(String[] args) throws Exception{
		// 我们在main方法中创建两个CompletableFuture对象,分别从新浪和网易获取同一个证券的价格
		CompletableFuture<StockPrice> getStockFromSina = CompletableFuture.supplyAsync(new StockFromSina());
		CompletableFuture<StockPrice> getStockFromNetease = CompletableFuture.supplyAsync(new StockFromNetease());
		// 并行的从新浪和网易获取证券的价格
		// 同时通过CompletableFuture.anyOf把两个CompletableFuture对象
		CompletableFuture<Object> getStock = CompletableFuture.anyOf(getStockFromSina, getStockFromNetease);
		// 当两个结果都返回的时候才执行,这时CompletableFuture的泛型参数是Void
		// CompletableFuture<Void> getStock = CompletableFuture.allOf(getStockFromSina, getStockFromNetease);
		// thenAccept会在两个中的任意一个完成的时候调用,这样我们打印的是先返回的证券代码
		getStock.thenAccept(new Consumer<Object>() {
			public void accept(Object result){
				System.out.println("Result: " + result);
			}
		});
		getStock.join();
	}
}
// 输出结果有时候是新浪先返回,有时候是网易先返回

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

1. thenAccept()处理正常结果

2. exceptional()处理异常结果

3. thenApplyAsync()用于串行化另一个CompletableFuture

4. anyOf/AllOf用于并行化两个CompletableFuture

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值