主线程等待所有子线程结束的4种方法,包括使用
CountDownLatch
、
CyclicBarrier
、
Future.get()
、
Completable.allOf()
。
主线程不等待子线程全部结束
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
int index = i;
executor.submit(() -> {
System.out.println("子线程" + index);
});
}
System.out.println("主线程-----");
}
}
结果如下:
子线程0
子线程3
子线程5
主线程-----
子线程1
子线程7
子线程8
子线程9
子线程6
子线程4
子线程2
1、使用CountDownLatch
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
CountDownLatch count = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
int index = i;
executor.submit(() -> {
try {
Thread.sleep(200);
System.out.println("子线程" + index);
count.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
count.await();
System.out.println("主线程-----");
long end = System.currentTimeMillis();
System.out.println("花费时间:" + (end - start));
}
}
结果如下:
子线程4
子线程1
子线程0
子线程2
子线程3
子线程9
子线程5
子线程6
子线程7
子线程8
主线程-----
花费时间:493
2、同步屏障CyclicBarrier
2.1、CyclicBarrier使用
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
long start = System.currentTimeMillis();
CyclicBarrier cyclicBarrier = new CyclicBarrier(11);
for (int i = 0; i < 10; i++) {
int index = i;
executor.submit(() -> {
try {
Thread.sleep(200);
System.out.println("子线程running" + index);
cyclicBarrier.await();
System.out.println("子线程end***" + index);
} catch (Exception e) {
e.printStackTrace();
}
});
}
System.out.println("主线程running@@@");
cyclicBarrier.await();
System.out.println("主线程end-----");
long end = System.currentTimeMillis();
System.out.println("花费时间:" + (end - start));
}
}
结果如下:
主线程running@@@
子线程running5
子线程running7
子线程running6
子线程running8
子线程running9
子线程running1
子线程running0
子线程running2
子线程running3
子线程running4
子线程end***4
主线程end-----
花费时间:289
子线程end***6
子线程end***5
子线程end***7
子线程end***8
子线程end***0
子线程end***3
子线程end***2
子线程end***9
子线程end***1
由代码和执行结果可以看出:
- 屏障拦截数要算上主线程即:屏障拦截数量=子线程数量+主线程数量(11=10+1)
- 主线程也要调用
await()
- 主线程会等待所有子线程到达屏障(调用
await()
) - 主线程无法控制子线程到达屏障(调用
await()
)后的操作,所以子线程调用await()要放在最后 - 如果使用线程池,线程池核心线程数要大于等于屏障拦截数
2.2、CyclicBarrier复用
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
long start = System.currentTimeMillis();
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
System.out.println("主线程end----");
long end = System.currentTimeMillis();
System.out.println("花费时间:" + (end - start));
});
for (int i = 0; i < 10; i++) {
int index = i;
executor.submit(() -> {
try {
Thread.sleep(200);
System.out.println("子线程running" + index);
cyclicBarrier.await();
System.out.println("子线程end***" + index);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
}
结果如下:
2.3、CountDownLatch和CyclicBarrier的区别
-
CountDownLatch
表示所有子线程一个一个执行完毕,子线程执行完之前主线程阻塞。 -
CyclicBarrier
表示所有子线程全部到达一个障碍屏障前,然后一起执行完毕,和主线程无关。 -
CountDownLatch
基于AQS
实现,CyclicBarrier
基于ReenTrantLock
+Condition
实现
就像田径比赛一样,CountDownLatch
每次countDown()
减一表示一个参赛者冲过终点线,全部通过,比赛结束。CyclicBarrier
相当于在终点线前设置一个障碍,所有参赛者到达障碍前,然后撤掉障碍手拉手通过终点线。CyclicBarrier
的复用就跟“车满发车”一个道理,乘客陆续上车,车满发车。
3、使用Future.get()
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
List<Future> futureList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int index = i;
Future future = executor.submit(() -> {
try {
Thread.sleep(200);
System.out.println("子线程running" + index);
} catch (Exception e) {
e.printStackTrace();
}
});
futureList.add(future);
}
for (Future future : futureList) {
//监听线程池子线程执行状态及执行结果。
future.get();
}
System.out.println("主线程end-----");
long end = System.currentTimeMillis();
System.out.println("花费时间:" + (end - start));
}
}
结果如下
子线程running7
子线程running4
子线程running6
子线程running5
子线程running1
子线程running3
子线程running2
子线程running8
子线程running9
子线程running0
主线程end-----
花费时间:303
4、使用Completable.allOf()
public class WaitThreadsDemo {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 100L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
List<CompletableFuture> futureList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int index = i;
CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟两次异常
if (index % 7 ==0){
int tmp = index/0;
}
System.out.println("子线程running" + index);
return "success";
},executor).exceptionally(e-> e.getMessage());
futureList.add(future);
}
//allOf()等待所有线程执行完毕
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
//但是allOf()拿不到执行结果,需要再次回调获取结果
CompletableFuture<List<String>> finalFutures = allFutures.thenApply(v-> futureList.stream().map(CompletableFuture<String>::join).collect(Collectors.toList()));
System.out.println(finalFutures.get());
//也可以直接使用最初的futureList集合获取结果,如下两行:
//List<String> resultList = futureList.stream().map(CompletableFuture<String>::join).collect(Collectors.toList());
//System.out.println(resultList);
System.out.println("主线程end-----");
long end = System.currentTimeMillis();
System.out.println("花费时间:" + (end - start));
}
}
结果如下:文章来源:https://www.toymoban.com/news/detail-625229.html
子线程running6
子线程running5
子线程running4
子线程running3
子线程running2
子线程running1
子线程running9
子线程running8
[java.lang.ArithmeticException: / by zero, success, success, success, success, success, success, java.lang.ArithmeticException: / by zero, success, success]
主线程end-----
花费时间:313
allOf()
没有返回值,拿不到执行结果,需要再次使用回调函数获取最初futureList
的执行结果。其实可以直接遍历futureList
获取结果。CompletableFuture
的详细使用:CompletableFuture使用详解文章来源地址https://www.toymoban.com/news/detail-625229.html
到了这里,关于主线程等待所有子线程结束的4种方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!