JDK1.8新特性CompletableFuture的使用demo
package cn.test.completable.future;
import cn.test.completable.future.pojo.Product;
import com.alibaba.fastjson.JSON;
import org.junit.Test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 注意 : 尽可能使用CompletableFuture的get方法来阻塞主线程结束而子线程也跟随结束的问题。万一遇到某些特殊情况可以考虑使用Atomic相关的特性来处理
*/
public class CompletableTest {
/**
* 当任务执行成功 ,结束后执行 thenAcceptAsync 。。。。。
* 当任务执行失败,则执行:exceptionally
*
* @throws InterruptedException
*/
@Test
public void test1() throws Exception {
Product product = new Product();
//线程需要处理的业务逻辑
CompletableFuture<Product> completableFuture = CompletableFuture.supplyAsync(() -> {
product.setName(getProductName());
return product;
});
//线程执行成功,没有异常执行thenAccept
completableFuture.thenAccept(result -> {
System.out.println("获取产品名称成功,产品名称:" + result.getName());
});
//线程执行失败,产生异常执行exceptionally
completableFuture.exceptionally((e) -> {
System.out.println("!!!!获取名称异常!!!!!");
e.printStackTrace();
return null;
});
completableFuture.get();
}
/**
* 任务的串行测试 按指定的业务顺序逐步执行完成
*/
@Test
public void test2() throws ExecutionException, InterruptedException {
Product product = new Product();
//第一步获取名称
CompletableFuture<Product> completableFutureFirst = CompletableFuture.supplyAsync(() -> {
System.out.println("-------第一步获取名称---------");
product.setName(getProductName());
return product;
});
//第二步获取code 代码
CompletableFuture<Product> completableFutureSecond = completableFutureFirst.thenApplyAsync((result) -> {
if (result != null) {
System.out.println("-------第二步获取code---------");
String code = queryCode(result.getName(), "https://finance.sina.com.cn/code/");
result.setCode(code);
}
return result;
});
//第三步获取price
CompletableFuture<Product> lastCompletableFuture = completableFutureSecond.thenApplyAsync((result) -> {
if (result != null) {
System.out.println("-------第三步获取price---------");
Double price = getPrice(result.getCode());
result.setPrice(price);
}
return result;
});
//最后完成阶段,如果是按顺序串行执行,此时最后返回的结果可以用get方法或者thenAccept都可以
lastCompletableFuture.thenAccept((result) -> {
Object o = JSON.toJSON(result).toString();
System.out.println("最后的结果用thenAccept来获取:" + o);
});
//这里用 lastCompletableFuture.get()可以获取最后的返回结果,按照一定的业务逻辑顺序串行执行,接收结果用get方法,
Product product1 = lastCompletableFuture.get();//自动阻塞主线程结束,当supplyAsync的业务逻辑执行完成则会自动调用get
System.out.println("最后的结果用get方法获取:" + JSON.toJSON(product1).toString());
}
/**
* 任务的并行测试使用anyOf,只要其中一个子线程线束就获取返回结果。不会再次获取后结束的子线程返回的结果
* 假设获取:名称、代码、价格三个属性并行进行
*/
@Test
public void test3() throws InterruptedException, ExecutionException {
AtomicBoolean flag = new AtomicBoolean(true);
//第一步获取名称
Product result = new Product();
CompletableFuture<Product> completableFutureFirst = CompletableFuture.supplyAsync(() -> {
//假设第一步获取名称需要10秒以上才能完成
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("-------第一步获取名称---------");
result.setName(getProductName());
return result;
});
//第二步获取code 代码 与第一步异步执行,调试使用anyOf执行
CompletableFuture<Product> completableFutureSecond = CompletableFuture.supplyAsync(() -> {
//假设第二步获取code需要5秒以上才能完成
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (result != null) {
System.out.println("-------第二步获取code---------");
String code = queryCode(result.getName(), "https://finance.sina.com.cn/code/");
result.setCode(code);
}
return result;
});
//第三步获取price 与前面两个线程并行执行
CompletableFuture<Product> completableThird = CompletableFuture.supplyAsync(() -> {
if (result != null) {
System.out.println("-------第三步获取price---------");
Double price = getPrice(result.getCode());
result.setPrice(price);
}
return result;
});
CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(completableFutureFirst, completableFutureSecond, completableThird);
//如果是anyOf这里的thenAccept会被执行,此时用:thenAccept 或者 get来接收返回结果都可以
objectCompletableFuture.thenAccept((obj) -> {
//只要其中任何一个supplyAsync执行完成,这里的代码就会被执行
//这里的代码只会被执行一次,这里执行结束后,当主线程结束后,即使其他线程的supplyAsync方法逻辑即使没有执行完成也会自动结束
Object o = JSON.toJSON(result).toString();
System.out.println("最后的结果:" + o);
flag.set(false);
});
Object obj = objectCompletableFuture.get();
if (obj instanceof Product) {
Product p = (Product) obj;
System.out.println("obj:" + JSON.toJSON(p).toString());
}
System.out.println("主线程结束");
}
/**
* 任务的并行测试使用allof ,这种是无序的,但必须都执行完才会往下执行
*
* @throws InterruptedException
*/
@Test
public void test4() throws InterruptedException, ExecutionException {
//第一步获取名称
Product result = new Product();
CompletableFuture<Product> completableFutureFirst = CompletableFuture.supplyAsync(() -> {
//假设第一步获取名称需要10秒以上才能完成
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result.setName(getProductName());
System.out.println("-------第一步获取名称 结束---------");
return result;
});
//第二步获取code 代码 与第一步异步执行,调试使用anyOf执行
CompletableFuture<Product> completableFutureSecond = CompletableFuture.supplyAsync(() -> {
//假设第二步获取code需要5秒以上才能完成
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (result != null) {
String code = queryCode(result.getName(), "https://finance.sina.com.cn/code/");
result.setCode(code);
}
System.out.println("-------第二步获取code 结束---------");
return result;
});
//第三步获取price 与前面两个线程并行执行
CompletableFuture<Product> completableThird = CompletableFuture.supplyAsync(() -> {
if (result != null) {
Double price = getPrice(result.getCode());
result.setPrice(price);
}
System.out.println("-------第三步获取price 结束---------");
return result;
});
//只要其中任何一个执行完成就打印信息
CompletableFuture<Void> allCompletableFuture = CompletableFuture.allOf(completableFutureFirst, completableFutureSecond, completableThird);
allCompletableFuture.thenAccept((obj) -> {
//这里的代码只会被执行一次,此时接收最后的结果只能用thenAccept来接收最后的结果
Object o = JSON.toJSON(result).toString();
System.out.println("最后的结果:" + o);
});
//这里调用get主要解决不让主线程立刻结束,主线程一旦结束,各个线程supplyAsync对应的业务逻辑也会被停止执行,allOf这种情况用get无法接收最后的结果,
//allOf返回的是void类型,则表示无返回结果
//如果把代码写成: Void aVoid = allCompletableFuture.get();发现会报异常,此时只能写成:allCompletableFuture.get();
allCompletableFuture.get();//这里作用于阻塞主线程,防止主线程立刻结束,不返回任何结果。
}
private String getProductName() {
double random = Math.random();
if (random > 0.7) {
throw new RuntimeException("名称异常");
}
return "中国石油";
}
private String queryCode(String name, String url) {
try {
Thread.sleep((long) (Math.random() * 100));
} catch (InterruptedException e) {
}
return "601857";
}
private Double getPrice(String code) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
return 5 + Math.random() * 20;
}
}
第一次写文章,注释不对,或者发现代码不对的地方欢迎指正