2021-09-14

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

}

第一次写文章,注释不对,或者发现代码不对的地方欢迎指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值