如何让主线程等待所有线程结束之后再执行
1、Future的机制,使用Future.get()阻塞等待结果(Future,FutureTask)
2、CountDownLatch同步工具类,此类的作用就是一个线程等待所有线程结束之后再执行
3、CompletableFuture 与Future机制类似,同样是使用get阻塞等待结果,不过此类可以使任务并行合并以及串行,相当于是Future的增强版
4、线程池的isTerminated方法,当调用shutdown()方法后,并且所有提交的任务完成后才会返回为true
5、Thread的join方法,等待主线程结束
Future机制
FutureTask
package com.alibaba.fescar.core.protocol.test;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class TestFuture {public static void main(String[] args) {FutureTask<Integer> futureTask = new FutureTask<Integer>(()-> {System.out.println("当前线程执行");return 1;});new Thread(futureTask).start();try {// 阻塞获取值Integer integer = futureTask.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("主线程执行");}}
执行结果
Future
package com.alibaba.fescar.core.protocol.test;import java.util.concurrent.*;public class TestFuture {public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(1);Future<Integer> task = pool.submit(() -> {System.out.println("当前线程执行");return 1;});try {// 阻塞获取结果Integer integer= task.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("主线程执行");}}
执行结果
结果分析:这里借用线程池提交任务,程序没有退出,是因为线程池没有shutdown,熟悉下线程池的submit方法
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
如上所示,线程池接受Callable 和Runnable任务,返回Future接口的上转型对象,和FutureTask同理,
有关于Runnable、Future、Callable、FutureTask 请参考文章:
Runnable、Future、Callable、FutureTask
CountDownLatch
package com.alibaba.fescar.core.protocol.test;import java.util.concurrent.CountDownLatch;public class TestCountDown {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(1);new Thread(() -> {System.out.println("当前线程结束");latch.countDown();}).start();latch.await();System.out.println("主线程结束");}}
执行结果
latch.dountDown()调用,计数器会减一,latch.await()会阻塞主线程直到0放行
CompletableFuture
package com.alibaba.fescar.core.protocol.test;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class TestCompletableFuture {public static void main(String[] args) throws ExecutionException, InterruptedException {/*** supplyAsync与runAsync的区别在于:supplyAsync有返回值,而runAsync没有返回值*/CompletableFuture<Integer> current1 = CompletableFuture.supplyAsync(() -> {System.out.println("当前线程1执行");return 3;});/*** 合并两个任务,两个任务可以同时执行,都执行成功后,执行最后的BiFunction操作。*/CompletableFuture<Integer> current2 = CompletableFuture.supplyAsync(() -> {System.out.println("当前线程2执行");return 2;}).thenCombine(current1,(res1,res2)->res1 * res2);System.out.println(current2.get());System.out.println("主线程执行");}
}
执行结果
CompletableFuture实现了Future接口,当其get的时候同样阻塞主线程执行, CompletableFuture在于可以多任务串行,以及并行执行,操作空间更广
具体用法请参考文章:CompletableFuture用法
线程池的isTerminated方法
package com.alibaba.fescar.core.protocol.test;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TestThreadPool{public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(3);pool.execute(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}});pool.execute(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}});pool.shutdown();while (true) {if (pool.isTerminated()) {System.out.println("线程池中的任务执行结束");break;}}System.out.println("主线程结束");}}
执行结果
isTerminated,当调用shutdown()方法后,并且所有提交的任务完成后才会返回为true
Thread的join方法
package com.alibaba.fescar.core.protocol.test;public class TestThreadJoin {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {System.out.println("t1执行");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});t1.start();Thread t2 = new Thread(() -> {try {System.out.println("t2执行");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});t2.start();t1.join();t2.join();System.out.println("主线程结束");}
}
执行结果
Thread中的join方法,用于等待本线程结束,同时阻塞其他线程,也叫插队线程,yeild线程礼让,让出执行权,wait 线程等待,释放锁, sleep线程休眠 不会释放锁