1. 基础概念以及基础方法

1.1 Thread.join()方法

thread1.join()

官网链接:https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

join(long millis)
Waits at most millis milliseconds for this thread to die.

join方法,带时间的,是等待至少给定的millis 毫秒,等待当前线程死去。
学习的时候老是会看到有人用,但是每次都是记了忘,忘了记忆。尝试着理解下。
使用时的动作:阻塞主线程,等待thread1执行完主线程再执行。
理解:join,含义:加入。表示这个线程thread1加入了主线程,成为了主线程的一部分,所以主线程会阻塞(完全是现在的理解,等之后查阅资料后再来修改)

1.2 Thread.sleep()方法

static void sleep(long millis)

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.

翻译:造成当前执行的线程睡眠指定的毫秒数,受系统计时器和调度程序的精度和准确性的影响
所以是让当前的线程睡眠,是一个静态方法,所以是Thread类来调用的。而不是当前类实际例。

2.CompletableFuture学习

2.1官方文档

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html

2.2 runAsync()方法和supplyAsync()方法

这两个方法用的比较多

static CompletableFuture<Void> runAsync(Runnable runnable)

Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() after it runs the given action.

首先runAsync是个静态方法。再来翻译下官网的方法注释:返回一个新的CompletableFuture,它在完成给定的动作后,会由运行在ForkJoinPool.commonPool()的任务异步完成

翻译看上去还是不是特别明白,但是实际使用的过程中和submit()一样,当前线程只管提交任务,任务的完成是在线程池里完成的。

static <U> CompletableFuture<U>	supplyAsync(Supplier<U> supplier)

Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() with the value obtained by calling the given Supplier.

同样是静态方法。尝试翻译:返回一个新的CompletableFuture,它被运行在ForkJoinPool.commonPool() 的任务完成,且完成时候会获得调用的给定的supplier的返回值。

使用过程中,是可以通过supplyAsync的返回值,拿到Supplier的返回值的。

代码test

 public static void main(String[] args) {
        CompletableFuture<Void> helloRunAsync = CompletableFuture.runAsync(() -> {
            System.out.format("####thread1 startTime:%d####\n", System.currentTimeMillis());
            Thread thread1 = Thread.currentThread();
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.format("this thread:%s,hello run async\n", thread1.getName());
            System.out.format("####thread1 endTime:%d####\n", System.currentTimeMillis());
        });
        CompletableFuture<String> helloSupplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.format("####thread2 startTime:%d####\n", System.currentTimeMillis());
            Thread thread2 = Thread.currentThread();
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.format("this thread:%s,hello supply async\n", thread2.getName());
            System.out.format("####thread2 endTime:%d#####\n", System.currentTimeMillis());
            return "supply async return";
        });
        System.out.format("####thread1 join startTime:%d#####\n", System.currentTimeMillis());
        System.out.println(helloRunAsync.join());
        System.out.format("####thread1 join endTime:%d#####\n", System.currentTimeMillis());
        System.out.format("####thread2 join startTime:%d#####\n", System.currentTimeMillis());
        System.out.println(helloSupplyAsync.join());
        System.out.format("####thread2 join endTime:%d#####\n", System.currentTimeMillis());
    }

output

####thread1 startTime:1650192261693####
####thread2 startTime:1650192261694####
####thread1 join startTime:1650192261694#####
this thread:ForkJoinPool.commonPool-worker-2,hello supply async
this thread:ForkJoinPool.commonPool-worker-1,hello run async
####thread2 endTime:1650192266725#####
####thread1 endTime:1650192266725####
null
####thread1 join endTime:1650192266728#####
####thread2 join startTime:1650192266728#####
supply async return
####thread2 join endTime:1650192266729#####

Process finished with exit code 0

分析:

  1. 从输出1-3行可以看出来两个方法内部在join方法调用前,就已经开始了。
  2. thread1和thread2几乎是同时开始,同时结束的,在ForkJoinPool.commonPool中对应的是两个线程:ForkJoinPool.commonPool-worker-2和ForkJoinPool.commonPool-worker-1
  3. runAsync是没有返回值的,可以看到打印出来的是个null。
  4. supplyAsync的返回值就是在代码里return的:“supply async return”

查看CompletableFuture.join()方法的注释

Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally
当结束时候返回结果,或者抛出一个异常,如果异常完成时

2.3 allOf()方法

还是老规矩,先看官方文档

static CompletableFuture<Void>	allOf(CompletableFuture<?>... cfs)

Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete.

静态方法,翻译:返回一个新的CompletableFuture,这个CompletableFuture当所有给定的CompletableFutures完成时,他会被完成

对于这个…写法不太熟悉,去搜了下,…表示可变参数,可以传一个或多个指定类型的参数,也可以传一个数组。

public class Param {
    public static void main(String[] args) {
        Param p = new Param();
        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        p.testParam("a");
        p.testParam("1", "2", "3");
        p.testParam(list.toArray(new String[0]));

    }

    private void testParam(String... params) {
        for (String p : params) {
            System.out.println(p);
        }
    }
}
output:
a
1
2
3
one
two

allOf()代码

public class ConcurrentTest {
    public static void main(String[] args) {
        CompletableFuture<Void> helloRunAsync = CompletableFuture.runAsync(() -> {
            System.out.format("####thread1 startTime:%d####\n", System.currentTimeMillis());
            Thread thread1 = Thread.currentThread();
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.format("this thread:%s,hello run async\n", thread1.getName());
            System.out.format("####thread1 endTime:%d####\n", System.currentTimeMillis());
        });
        CompletableFuture<String> helloSupplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.format("####thread2 startTime:%d####\n", System.currentTimeMillis());
            Thread thread2 = Thread.currentThread();
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.format("this thread:%s,hello supply async\n", thread2.getName());
            System.out.format("####thread2 endTime:%d#####\n", System.currentTimeMillis());
            return "supply async return2";
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.format("####thread3 startTime:%d####\n", System.currentTimeMillis());
            Thread thread2 = Thread.currentThread();
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.format("this thread:%s,hello supply async\n", thread2.getName());
            System.out.format("####thread3 endTime:%d#####\n", System.currentTimeMillis());
            return "supply async return3";
        });
        List<CompletableFuture> futureList = new ArrayList<>();
        futureList.add(helloRunAsync);
        futureList.add(helloSupplyAsync);
        futureList.add(future2);
        CompletableFuture<Void> allFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
        try {
            System.out.format("-----main thread start:%d------\n", System.currentTimeMillis());
            allFuture.get(10, TimeUnit.SECONDS);
            System.out.format("-----main thread end:%d------\n", System.currentTimeMillis());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

output

####thread1 startTime:1650212196115####
####thread3 startTime:1650212196116####
####thread2 startTime:1650212196116####
-----main thread start:1650212196116------
this thread:ForkJoinPool.commonPool-worker-3,hello supply async
####thread3 endTime:1650212198155#####
this thread:ForkJoinPool.commonPool-worker-2,hello supply async
####thread2 endTime:1650212199150#####
this thread:ForkJoinPool.commonPool-worker-1,hello run async
####thread1 endTime:1650212201154####
-----main thread end:1650212201156------

Process finished with exit code 0

分析:创建了三个CompletableFuture,其中helloRunAsync是没有返回的,helloSupplyAsync和future2是有返回的。从结果里可以看出来,main thread end的确是发生在三个CompletableFuture中最晚一个完成后,才执行的。所以,可以使用allOf()方法结合get()方法,来达到我们并行执行多个任务,但是等待所有任务都结束后才一起返回结果的效果。

顺便贴下get()方法的描述

T	get(long timeout, TimeUnit unit)

Waits if necessary for at most the given time for this future to complete, and then returns its result, if available.

非静态方法,翻译:如果是必要的,最多等待给定的时间来完成这个future,然后返回它的结果,如果是可以获得的

2.4原理

todo: