Java充电社
专辑
博文
联系我
本人继续续收门徒,亲手指导
Java高并发教程
-> 等待线程完成的方式你知道几种?
1、必须知道的几个概念
2、并发级别
3、有关并行的两个重要定律
4、JMM相关的一些概念
5、深入理解进程和线程
6、线程的基本操作
7、volatile与Java内存模型
8、线程组
9、用户线程和守护线程
10、线程安全和synchronized
11、中断线程的几种方式
12、JUC中ReentrantLock
13、JUC中的Condition
14、JUC中的LockSupport工具类
15、UC中的Semaphore(信号量)
16、JUC中的CountDownLatch
17、JUC中的循环栅栏CyclicBarrier
18、线程池
19、JUC中的Executor框架详解1
20、JUC中的Executor框架详解2
21、java中的CAS
22、java中的UnSafe类
23、JUC中的原子操作类
24、ThreadLocal、InheritableThreadLocal
25、JUC中的阻塞队列
26、JUC中一些常见的集合
27、实战:你的接口太慢了需要优化
28、实战:构建日志系统
29、实战:一起来搞懂限流
30、JUC中的CompletableFuture
31、等待线程完成的方式你知道几种?
32、原子操作增强类LongAdder、LongAccumulator
33、怎么演示公平锁和非公平锁
34、谷歌提供的一些好用的并发工具类
35、延迟队列 DelayQueue 详解
36、线程6种状态详解
37、如何实现一个通用的延迟队列?
上一篇:JUC中的CompletableFuture
下一篇:原子操作增强类LongAdder、LongAccumulator
<div style="display:none"></div> java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: **在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有什么优缺点?** 结合这个需求,我们使用**6种方式**,来对之前学过的知识点做一个回顾,加深记忆。 ## 方式1:Thread的join()方法实现 代码: ```java package com.itsoku.chat31; import java.sql.Time; import java.util.concurrent.*; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo1 { //用于封装结果 static class Result<T> { T result; public T getResult() { return result; } public void setResult(T result) { this.result = result; } } public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); //用于存放子线程执行的结果 Result<Integer> result = new Result<>(); //创建一个子线程 Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); result.setResult(10); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); //让主线程等待thread线程执行完毕之后再继续,join方法会让当前线程阻塞 thread.join(); //获取thread线程的执行结果 Integer rs = result.getResult(); System.out.println(System.currentTimeMillis()); System.out.println(System.currentTimeMillis() + ":" + rs); } } ``` 输出: ```java 1566733162636 1566733165692 1566733165692:10 ``` 代码中通过join方式阻塞了当前主线程,当thread线程执行完毕之后,join方法才会继续执行。 关于join()方法和线程更详细的使用,可以参考:[线程的基本操作](/course/1/6) ## 方式2:CountDownLatch实现 代码: ```java package com.itsoku.chat31; import java.util.concurrent.*; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo2 { //用于封装结果 static class Result<T> { T result; public T getResult() { return result; } public void setResult(T result) { this.result = result; } } public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); CountDownLatch countDownLatch = new CountDownLatch(1); //用于存放子线程执行的结果 Demo1.Result<Integer> result = new Demo1.Result<>(); //创建一个子线程 Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); result.setResult(10); } catch (InterruptedException e) { e.printStackTrace(); }finally { countDownLatch.countDown(); } }); thread.start(); //countDownLatch.await()会让当前线程阻塞,当countDownLatch中的计数器变为0的时候,await方法会返回 countDownLatch.await(); //获取thread线程的执行结果 Integer rs = result.getResult(); System.out.println(System.currentTimeMillis()); System.out.println(System.currentTimeMillis() + ":" + rs); } } ``` 输出: ```java 1566733720406 1566733723453 1566733723453:10 ``` 上面代码也达到了预期效果,使用`CountDownLatch`可以让一个或者多个线程等待一批线程完成之后,自己再继续;`CountDownLatch`更详细的介绍见:[JUC中等待多线程完成的工具类CountDownLatch,必备技能](/course/1/16) ## 方式3:ExecutorService.submit方法实现 代码: ```java package com.itsoku.chat31; import java.util.concurrent.*; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建一个线程池 ExecutorService executorService = Executors.newCachedThreadPool(); System.out.println(System.currentTimeMillis()); Future<Integer> future = executorService.submit(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); //关闭线程池 executorService.shutdown(); System.out.println(System.currentTimeMillis()); Integer result = future.get(); System.out.println(System.currentTimeMillis() + ":" + result); } } ``` 输出: ```java 1566734119938 1566734119989 1566734122989:10 ``` 使用`ExecutorService.submit`方法实现的,此方法返回一个`Future`,`future.get()`会让当前线程阻塞,直到Future关联的任务执行完毕。 相关知识: 1. [JAVA线程池,这一篇就够了](/course/1/18) 2. [JUC中的Executor框架详解1](/course/1/19) 3. [JUC中的Executor框架详解2](/course/1/20) ## 方式4:FutureTask方式1 代码: ```java package com.itsoku.chat31; import java.util.concurrent.*; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo4 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); //创建一个FutureTask FutureTask<Integer> futureTask = new FutureTask<>(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); //将futureTask传递一个线程运行 new Thread(futureTask).start(); System.out.println(System.currentTimeMillis()); //futureTask.get()会阻塞当前线程,直到futureTask执行完毕 Integer result = futureTask.get(); System.out.println(System.currentTimeMillis() + ":" + result); } } ``` 输出: ```java 1566736350314 1566736350358 1566736353360:10 ``` 代码中使用`FutureTask`实现的,FutureTask实现了`Runnable`接口,并且内部带返回值,所以可以传递给Thread直接运行,`futureTask.get()`会阻塞当前线程,直到`FutureTask`构造方法传递的任务执行完毕,get方法才会返回。关于`FutureTask`详细使用,请参考:[JUC中的Executor框架详解1](https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933156&idx=1&sn=30f7d67b44a952eae98e688bc6035fbd&chksm=88621b1abf15920c7a0705fbe34c4ce92b94b88e08f8ecbcad3827a0950cfe4d95814b61f538&token=995072421&lang=zh_CN&scene=21#wechat_redirect) ## 方式5:FutureTask方式2 代码: ```java package com.itsoku.chat31; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo5 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); //创建一个FutureTask FutureTask<Integer> futureTask = new FutureTask<>(() -> 10); //将futureTask传递一个线程运行 new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } futureTask.run(); }).start(); System.out.println(System.currentTimeMillis()); //futureTask.get()会阻塞当前线程,直到futureTask执行完毕 Integer result = futureTask.get(); System.out.println(System.currentTimeMillis() + ":" + result); } } ``` 输出: ```java 1566736319925 1566736319970 1566736322972:10 ``` 创建了一个`FutureTask`对象,调用`futureTask.get()`会阻塞当前线程,子线程中休眠了3秒,然后调用`futureTask.run();`当futureTask的run()方法执行完毕之后,`futureTask.get()`会从阻塞中返回。 注意:这种方式和方式4的不同点。 关于`FutureTask`详细使用,请参考:[JUC中的Executor框架详解1](/course/1/19) ## 方式6:CompletableFuture方式实现 代码: ```java package com.itsoku.chat31; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; /** * 跟着阿里p7学并发,微信公众号:javacode2018 */ public class Demo6 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); System.out.println(System.currentTimeMillis()); //futureTask.get()会阻塞当前线程,直到futureTask执行完毕 Integer result = completableFuture.get(); System.out.println(System.currentTimeMillis() + ":" + result); } } ``` 输出: ```java 1566736205348 1566736205428 1566736208429:10 ``` `CompletableFuture.supplyAsync`可以用来异步执行一个带返回值的任务,调用`completableFuture.get()` 会阻塞当前线程,直到任务执行完毕,get方法才会返回。 关于`CompletableFuture`更详细的使用见:[JUC中工具类CompletableFuture,必备技能](/course/1/30) <a style="display:none" target="_blank" href="https://mp.weixin.qq.com/s/_S1DD2JADnXvpexxaBwLLg" style="color:red; font-size:20px; font-weight:bold">继续收门徒,亲手带,月薪 4W 以下的可以来找我</a> ## 最新资料 1. <a href="https://mp.weixin.qq.com/s?__biz=MzkzOTI3Nzc0Mg==&mid=2247484964&idx=2&sn=c81bce2f26015ee0f9632ddc6c67df03&scene=21#wechat_redirect" target="_blank">尚硅谷 Java 学科全套教程(总 207.77GB)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484192&idx=1&sn=505f2faaa4cc911f553850667749bcbb&scene=21#wechat_redirect" target="_blank">2021 最新版 Java 微服务学习线路图 + 视频</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484573&idx=1&sn=7f3d83892186c16c57bc0b99f03f1ffd&scene=21#wechat_redirect" target="_blank">阿里技术大佬整理的《Spring 学习笔记.pdf》</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484544&idx=2&sn=c1dfe907cfaa5b9ae8e66fc247ccbe84&scene=21#wechat_redirect" target="_blank">阿里大佬的《MySQL 学习笔记高清.pdf》</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485167&idx=1&sn=48d75c8e93e748235a3547f34921dfb7&scene=21#wechat_redirect" target="_blank">2021 版 java 高并发常见面试题汇总.pdf</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485664&idx=1&sn=435f9f515a8f881642820d7790ad20ce&scene=21#wechat_redirect" target="_blank">Idea 快捷键大全.pdf</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/1/2883e86e-3eff-404a-8943-0066e5e2b454.png)
#custom-toc-container