Powerful CompletableFuture

Primer

To make the program more efficient, so that the maximum efficiency of CPU work, we will use asynchronous programming. First thought is to open a new thread to do a particular job. Still further, in order to allow the new thread can return a value that tells the main thread of things done, and thus Future on stage. However, the way the main thread is provided by Future initiative inquiries new thread, if there is a callback function to cool. Therefore, in order to meet some regret, powerful CompletableFuture Future With a Java8 up.

Future

Traditional multi-threaded program allows more efficient, asynchronous, after all, can allow the CPU to work fully, but only in newly opened without having to thread your main thread again bother. For example, you open a new thread just to calculate 1 + ... + n and then print the results. Sometimes you need to return the child thread the results, further calculations were performed on the main thread, we need the Future.

See the following example, the main thread is calculated 2 + 4 + 8 + 10 + 6; calculating child threads 1 + 3 + 5 + 7 + 9; Finally two partial results are added again in the main thread.

public class OddNumber implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        Thread.sleep(3000);
        int result = 1 + 3 + 5 + 7 + 9;
        return result;
    }
}
复制代码
public class FutureTest {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        OddNumber oddNumber = new OddNumber();
        Future<Integer> future = executor.submit(oddNumber);
        long startTime = System.currentTimeMillis();
        int evenNumber = 2 + 4 + 6 + 8 + 10;
        try {
            Thread.sleep(1000);
            System.out.println("0.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
            int oddNumberResult = future.get();//这时间会被阻塞
            System.out.println("1+2+...+9+10="+(evenNumber+oddNumberResult));
            System.out.println("1.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
输出结果:
0.开始了:1001秒
1+2+...+9+10=55
1.开始了:3002秒
复制代码

Look at the Future interfaces, only five relatively simple

//取消任务,如果已经完成或者已经取消,就返回失败
boolean cancel(boolean mayInterruptIfRunning);
//查看任务是否取消
boolean isCancelled();
//查看任务是否完成
boolean isDone();
//刚才用到了,查看结果,任务未完成就一直阻塞
V get() throws InterruptedException, ExecutionException;
//同上,但是加了一个过期时间,防止长时间阻塞,主线程也做不了事情
V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;
复制代码

CompletableFuture

The above five ways to see the Future, not very rich, since our main thread is called main, they should take the initiative, I hope the child thread to finish things take the initiative to inform me. To this end, Java8 brought CompletableFuture, a Future implementation class. In fact, the most charming places CompletableFuture not greatly enriched the Future of features, but combines new features Java8 flow.

Implement a callback, automatic follow-up operation

Say in advance what method (one) CompletableFuture implement callback: thenAccept ()

    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(null, action);
    }
复制代码

There is a parameter Consumer, uses Java8 new features, parameterized behavior is not necessarily a basic parameter type or class, can also be a function of (behavior), or a method (interfaces).

public class OddNumberPlus implements Supplier<Integer> {
    @Override
    public Integer get() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1+3+5+7+9;
    }
}
复制代码
public class CompletableFutureTest {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        final int evenNumber = 2 + 4 + 6 + 8 + 10;
        CompletableFuture<Integer> oddNumber = CompletableFuture.supplyAsync(new OddNumberPlus());
        try {
            Thread.sleep(1000);
            System.out.println("0.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
            //看这里,实现回调
            oddNumber.thenAccept(oddNumberResult->
                        {
                            System.out.println("1.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
                            System.out.println("此时计算结果为:"+(evenNumber+oddNumberResult));
                        });
            oddNumber.get();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
输出结果:
0.开始了:1006秒
1.开始了:3006秒
此时计算结果为:55
复制代码

It is worth mentioning that, in this case does not show the connection pool to create a task, the program will select a default task connection pool ForkJoinPool.commonPool ()

    private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
复制代码

ForkJoinPool began JDK7, called a branch / coupling frame. A task can be divided into many molecules by recursive task, different streams formed, for parallel execution, also accompanied by a strong work-stealing algorithm. Greatly improve efficiency. Of course, you can also specify their own connection pool.

CompletableFuture merger

Java8 indeed enriched the Future realization, CompletableFuture there are many ways for everyone to use, but the above example but, in fact, do CompletableFuture function, seemingly Future. After all, you CompletableFuture use get () method when this is not blocked, I can quite Future's got a return value, and then manually perform some action thing (although this main method must be very uncomfortable). Then the next thing, Future done will be very troublesome. We assume that the main method only even-odd collection plus a collection of this operation, the operation asynchronous considered in advance of the two collections to the two sub-thread, how do we need it? Yes, open two threads, until the end of the two threads are counted, we were finally added, the question is, how do you know that the child thread finally ended it? (Looks like you can make a poll, uncertain calls isDone () This method ...) rich CompletableFuture function provides us with a method for waiting two sub-thread over, then add operation:

    //asyncPool就是上面提到的默认线程池ForkJoinPool
    public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(asyncPool, other, fn);
    }
复制代码

Look at an example:

public class OddCombine implements Supplier<Integer> {
    @Override
    public Integer get() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1+3+5+7+9;
    }
}
复制代码
public class EvenCombine implements Supplier<Integer> {
    @Override
    public Integer get() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 2+4+6+8+10;
    }
}

复制代码
public class CompletableCombineTest {
    public static void main(String[] args) throws Exception{
        CompletableFuture<Integer> oddNumber = CompletableFuture.supplyAsync(new OddCombine());
        CompletableFuture<Integer> evenNumber = CompletableFuture.supplyAsync(new EvenCombine());
        long startTime = System.currentTimeMillis();
        CompletableFuture<Integer> resultFuturn = oddNumber.thenCombine(evenNumber,(odd,even)->{
            return odd + even;
        });
        System.out.println(resultFuturn.get());
        System.out.println("0.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
    }
}
输出结果:
55
0.开始了:3000秒
复制代码

A simulated sleep one second side, a sleeping three seconds, but the real time network requests is uncertain. Is not so cool, succulent is not a phenomenon, but above operations have utilized the concept of Java8 flow.

Two sub-thread is not enough, then there ** anyOff () ** function, can withstand multiple CompletableFuture, waits until all tasks are completed.

    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }
复制代码

With its long like, there is a method, is executed when the first end, to end, behind the task not wait any longer, it can be regarded as a sufficient condition.

    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }
复制代码

On the basis of that of the above example, the modulation type time longer OddNumberPlus:

public class OddNumberPlus implements Supplier<Integer> {
    @Override
    public Integer get() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1+3+5+7+9;
    }
}
复制代码
public class CompletableCombineTest {
    public static void main(String[] args) throws Exception{
        CompletableFuture<Integer> oddNumber = CompletableFuture.supplyAsync(new OddCombine());
        CompletableFuture<Integer> evenNumber = CompletableFuture.supplyAsync(new EvenCombine());
        CompletableFuture<Integer> testNumber = CompletableFuture.supplyAsync(new OddNumberPlus());
        long startTime = System.currentTimeMillis();
        CompletableFuture<Object> resultFuturn = CompletableFuture.anyOf(oddNumber,evenNumber,testNumber);
        System.out.println(resultFuturn.get());
        System.out.println("0.开始了:"+ (System.currentTimeMillis()-startTime) +"秒");
    }
}
输出结果:
30
0.开始了:1000秒
复制代码

summary

CompletableFuture fact there are many methods, for example, commonly used runAsync (), similar supplyAsync (), but no return value; except thenApply () callback function can be added outside, as well as thenApply (); also injected runAfterBoth (), runAfterEither (), which is intended to see to know the name. There are many, we can point to open source CompletableFuture a closer look at this class. See around corners, through CompletableFuture, Java8 feel more powerful, powerful streaming concept, parameterized behavior, efficient parallel concepts, etc., will not only allow Java to write Gengshuang, Java also continue to enrich the entire ecosystem. Java has been in progress, it has not been eliminated by the times, we Javaer can continue his career, thanks to Java, progress together.

Guess you like

Origin juejin.im/post/5d307367e51d455d850d3ba4