completablefuture初识

在开始学习completablefuture,发现他是Future的升级,所以先来了解一下Future

一 Future–interface

在并发编程中,我们经常用到非阻塞的模型,在之前的多线程的三种实现中,不管是继承thread类还是实现runnable接口,都无法保证获取到之前的执行结果。通过实现Callback接口,并用Future可以来接收多线程的执行结果。
Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。
举个例子:比如去吃早点时,点了包子和凉菜,包子需要等3分钟,凉菜只需1分钟,如果是串行的一个执行,在吃上早点的时候需要等待4分钟,但是因为你在等包子的时候,可以同时准备凉菜,所以在准备凉菜的过程中,可以同时准备包子,这样只需要等待3分钟。那Future这种模式就是后面这种执行模式。

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning); //还没计算完,可以取消计算过程

    boolean isCancelled();  //判断计算是否被取消

    boolean isDone(); //判断是否计算完

    V get() throws InterruptedException, ExecutionException;  //获取计算结果(如果还没计算完,也是必须等待的)

    V get(long timeout, TimeUnit unit)	//最多等待timeout的时间就会返回结果
        throws InterruptedException, ExecutionException, TimeoutException;
}

FutureTask是Future接口的一个唯一实现类。 所以在使用Future时候是使用FutureTask+Callable,因为callable有返回值。

二 Future的局限性

Future接口可以构建异步应用,但依然有其局限性。它很难直接表述多个Future 结果之间的依赖性。实际开发中,我们经常需要达成以下目的:

  • 将两个异步计算合并为一个——这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果。
  • 等待 Future 集合中的所有任务都完成。
  • 仅等待 Future集合中最快结束的任务完成(有可能因为它们试图通过不同的方式计算同一个值),并返回它的结果。
  • 通过编程方式完成一个Future任务的执行(即以手工设定异步操作结果的方式)。
  • 应对 Future 的完成事件(即当 Future的完成事件发生时会收到通知,并能使用 Future 计算的结果进行下一步的操作,不只是简单地阻塞等待操作的结果)

新的CompletableFuture类将使得这些成为可能。

三 CompletableFuture

一些使用经验:

1,自定义线程池比list小的时候,线程池全部被占用,线程池队列占满,其他的任务也没有被丢弃,至于怎么实现的还没搞清楚,有理解的朋友 欢迎留言或私信告知。

a 创建任务

CompletableFuture源码中有四个静态方法用来执行异步任务:

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor){..}

public static CompletableFuture<Void> runAsync(Runnable runnable){..}

public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor){..} 

上述方法前两个都是返回一个新的CompletableFuture,如果给定线程池则用给定的线程池,如果不给的话使用默认的ForkJoinPool.commonPool(),有人说自己给定效果好,没验证,不过自己给定好对线程池进行控制。
前面两个是有返回值的,后面两个是没有返回值的。
执行异步任务的方式很简单

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    //....执行任务
    return "hello";}, executor)
b 获取执行结果的方法:
public boolean isDone()	// true如果以任何方式完成或通过取消。 
public T get() throws InterruptedException,ExecutionException 	//阻塞等待,然后返回结果。 
public T get(long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException //阻塞等待结果,超时抛异常
public T join()  //完成后返回结果值,如果完成异常,则返回(未检查)异常。 为了更好地符合常用功能形式的使用,如果完成此CompletableFuture涉及的计算抛出异常,则该方法将引发(未选中) CompletionException ,其中的基础异常是其原因。
public T getNow(T valueIfAbsent)	//如果已完成,则返回结果值(或抛出任何遇到的异常),否则返回给定的值IfAbsent。

get和join的区别
两者都是等待结果,但是get会让你显式的捕获异常,而join不强制捕获,但如果代码异常也会抛出。另外join不能被打断(can not get interrupted)。

public boolean complete(T value)
public boolean completeExceptionally(Throwable ex)

future.get()在等待执行结果时,程序会一直block,如果此时调用complete(T t)会立即执行。但是complete(T t)只能调用一次,后续的重复调用会失效。如果future已经执行完毕能够返回结果,此时再调用complete(T t)则会无效。
如果使用completeExceptionally(Throwable ex)则抛出一个异常,而不是一个成功的结果。(引用2)
下面是我的测试代码

@Test
    public void test2() {
        System.out.println(System.currentTimeMillis());
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "mission A";
            }
        });
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "mission B";
        });
        CompletableFuture<String> futureC = futureB.thenApplyAsync(b -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("canshu" + b  + System.currentTimeMillis());
            System.out.println("mission C action" + System.currentTimeMillis());
            return "mission C";
        });
        //you can change the code below to test the results
        try {
            if (!futureA.isDone()) {
                System.out.println(futureA.getNow("can't wait anymore"));
            }
            String join = futureA.join();
            try {
                futureA.get((long) 0.5, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            System.out.println(join);
            System.out.println(futureA.get() + System.currentTimeMillis());
            System.out.println(futureB.get() + System.currentTimeMillis());
            System.out.println(futureC.get() + System.currentTimeMillis());
            if (futureA.isDone()) {
                System.out.println("mission A is done");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
c CompletionStage

CompletionStage 代表异步计算中的一个阶段或步骤。
该接口定义了多种不同的方式,将CompletionStage 实例与其他实例或代码链接在一起,比如完成时调用的方法(一共 59 种方法,比Future 接口中的 5 种方法要多得多。)

d 其他方法 (引用1介绍的不错,比较好)

可以自己写一些小栗子加深理解

@Test
    public void test4() {
        System.out.println(System.currentTimeMillis());
        List<CreateOrderCarInfo> callList = Lists.newArrayList(new CreateOrderCarInfo("A"), new CreateOrderCarInfo("B"), new CreateOrderCarInfo("C"));
        List<CompletableFuture<String>> collect = callList.stream().map(carInfo -> CompletableFuture.supplyAsync(() -> carInfo.createChildOrder("public"))).collect(Collectors.toList());
        List<String> res = collect.stream().map(CompletableFuture::join).collect(Collectors.toList());
        for (String re : res) {
            if ("2".equals(re)) {
                System.out.println("didi" + System.currentTimeMillis());
                return;
            }
            if ("1".equals(re)) {
                System.out.println("fail" + System.currentTimeMillis());
                return;
            }
        }
        System.out.println("success" + System.currentTimeMillis());
    }
    public class CreateOrderCarInfo {

        private String privates;

        public CreateOrderCarInfo(String privates) {
            this.privates = privates;
        }

        public String createChildOrder(String carOrder) {
            double v = 1000 * Math.random() + 1000;
            int i = (int)(Math.random() * 3);
            try {
                Thread.sleep((long) v);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("new " + privates + System.currentTimeMillis());
            return privates + String.valueOf(i);
        }
    }

注:引用

1.https://blog.csdn.net/qq_42606051/article/details/84028376
2.https://blog.csdn.net/u012129558/article/details/78962759

猜你喜欢

转载自blog.csdn.net/weixin_43189126/article/details/87967763