三、Java8的CompletableFuture,Java的多线程开发

1、CompletableFuture的常用方法

  • 以后用到再加
  1. runAsync() :开启异步(创建线程执行任务),无返回值
  2. supplyAsync() :开启异步(创建线程执行任务),有返回值
  3. thenApply() :然后应用,适用于有返回值的结果,拿着返回值再去处理。
  4. exceptionally():用于处理异步任务执行过程中出现异常的情况的一个方法:返回默认值或者一个替代的 CompletableFuture 对象,从而避免系统的崩溃或异常处理的问题。
  5. handle():类似exceptionally()
  6. get() :阻塞线程:主要可以: ①获取线程中的异常然后处理异常、②设置等待时间
  7. join() :阻塞线程:推荐使用 join() 方法,因为它没有受到 interrupt 的干扰,不需要捕获异常,也不需要强制类型转换。他自己会抛出异常。
  8. CompletableFuture.allOf()
  9. CompletableFuture.anyOf()
  • get() 和 join() 方法区别?

    • 都可以阻塞线程 —— 等所有任务都执行完了再执行后续代码。
  1. CompletableFuture 中的 get() join() 方法都用于获取异步任务的执行结果,但是在使用时需要注意以下几点区别:
  2. 1. 抛出异常的方式不同:如果异步任务执行过程中出现异常, get() 方法会抛出 ExecutionException 异常,而 join() 方法会抛出 CompletionException 异常,这两个异常都是继承自 RuntimeException 的。
  3. 2. 方法调用限制不同: join() 方法是不可以被中断的,一旦调用就必须等待任务执行完成才能返回结果;而 get() 方法可以在调用时设置等待的超时时间,如果超时还没有获取到结果,就会抛出 TimeoutException 异常。
  4. 3. 返回结果类型不同: get() 方法返回的是异步任务的执行结果,该结果是泛型类型 T 的,需要强制转换才能获取真正的结果;而 join() 方法返回的是异步任务的执行结果,该结果是泛型类型 T,不需要强制转换。
  5. 4. 推荐使用方式不同:推荐在 CompletableFuture 中使用 join() 方法,因为它没有受到 interrupt 的干扰,不需要捕获异常,也不需要强制类型转换。
  6. 综上所述, get() 方法和 join() 方法都是获取异步任务的执行结果,但是在使用时需要根据具体场景选择使用哪个方法。如果需要获取执行结果并且不希望被中断,推荐使用 join() 方法;如果需要控制等待时间或者需要捕获异常,则可以使用 get() 方法。
  • anyOf() 和 allOf() 的区别?
  1. CompletableFuture Java 8 引入的一个强大的异步编程工具,它支持链式调用、组合和转换异步操作等功能。其中,anyOf allOf 都是 CompletableFuture 的两个常用方法,它们的区别如下:
  2. 1. anyOf:任意一个 CompletableFuture 完成,它就会跟随这个 CompletableFuture 的结果完成,返回第一个完成的 CompletableFuture 的结果。
  3. 2. allOf:所有的 CompletableFuture 都完成时,它才会跟随它们的结果完成,返回一个空的 CompletableFuture
  4. 简而言之,anyOf allOf 的最大区别是:anyOf 任意一个 CompletableFuture 完成就跟着它的结果完成,而 allOf 所有的 CompletableFuture 完成才可以完成,并返回一个空的 CompletableFuture
  5. 举例来说,如果有三个 CompletableFuturef1f2f3,其中 f1 f2 可能会返回一个字符串,而 f3 可能会返回一个整数,那么:
  6. - anyOf(f1, f2, f3) 的结果是 f1f2f3 中任意一个 CompletableFuture 的结果;
  7. - allOf(f1, f2, f3) 的结果是一个空的 CompletableFuture,它的完成状态表示 f1f2f3 是否全部完成。
  8. 总之,anyOf allOf 在实际使用中可以根据不同的需求来选择,它们都是 CompletableFuture 中非常强大的组合操作。

2、使用CompletableFuture

2.1、实体类准备

  1. package com.cc.md.entity;
  2. import lombok.Data;
  3. /**
  4. * @author CC
  5. * @since 2023/5/24 0024
  6. */
  7. @Data
  8. public class UserCs {
  9. private String name;
  10. private Integer age;
  11. }

2.2、常用方式

  • 无返回值推荐:开启多线程——无返回值的——阻塞:test06
  1. @Resource(name = "myIoThreadPool")
  2. private ThreadPoolTaskExecutor myIoThreadPool;
  3. //CompletableFuture开启多线程——无返回值的
  4. @Test
  5. public void test06() throws Exception {
  6. List<CompletableFuture<Void>> futures = new ArrayList<>();
  7. //循环,模仿很多任务
  8. for (int i = 0; i < 1000; i++) {
  9. int finalI = i;
  10. CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  11. //第一批创建的线程数
  12. log.info("打印:{}", finalI);
  13. //模仿io流耗时
  14. try {
  15. Thread.sleep(5000);
  16. } catch (InterruptedException e) {
  17. throw new RuntimeException(e);
  18. }
  19. }, myIoThreadPool);
  20. futures.add(future);
  21. }
  22. //阻塞:多线程的任务执行。相当于多线程执行完了,再执行后面的代码
  23. //如果不阻塞,上面的相当于异步执行了。
  24. //阻塞方式1:可以获取返回的异常、设置等待时间
  25. // futures.forEach(future -> {
  26. // try {
  27. // future.get();
  28. // } catch (Exception e) {
  29. // throw new RuntimeException(e);
  30. // }
  31. // });
  32. //阻塞方式2(推荐)
  33. CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
  34. log.info("打印:都执行完了。。。");
  35. }
  • 有返回值推荐:开启多线程——有返回值的,返回一个新的List——阻塞——使用stream流的map:test09

    • test07、test08 可以转化为 test09 (现在这个)
    • 可以返回任务类型的值,不一定要返回下面的user对象。
  1. @Resource(name = "myIoThreadPool")
  2. private ThreadPoolTaskExecutor myIoThreadPool;
  3. //CompletableFuture开启多线程——有返回值的,返回一个新的List——先有数据的情况——使用stream流的map
  4. //像这种,需要构建另一个数组的,相当于一个线程执行完了,会有返回值
  5. //使用stream流的map + CompletableFuture.supplyAsync()
  6. @Test
  7. public void test09() throws Exception {
  8. //先获取数据,需要处理的任务。
  9. List<UserCs> users = this.getUserCs();
  10. //莫法处理任务
  11. List<CompletableFuture<UserCs>> futures = users.stream()
  12. .map(user -> CompletableFuture.supplyAsync(() -> {
  13. // 处理数据
  14. user.setName(user.getName() + "-改");
  15. log.info("打印-改:{}", user.getName());
  16. // 其他的业务逻辑。。。
  17. return user;
  18. }, myIoThreadPool)).collect(Collectors.toList());
  19. //获取futures
  20. List<UserCs> endList = futures.stream()
  21. //阻塞所有线程
  22. .map(CompletableFuture::join)
  23. //取age大于10的用户
  24. .filter(user -> user.getAge() > 10)
  25. //按照age升序排序
  26. .sorted(Comparator.comparing(UserCs::getAge))
  27. .collect(Collectors.toList());
  28. log.info("打印:都执行完了。。。{}", endList);
  29. }

2.3、异常处理

  • exceptionally
  • handle
  1. //CompletableFuture 异常处理
  2. @Test
  3. public void test10() throws Exception {
  4. //先获取数据,需要处理的任务。
  5. List<UserCs> users = this.getUserCs();
  6. //莫法处理任务
  7. List<CompletableFuture<UserCs>> futures = users.stream()
  8. .map(user -> CompletableFuture.supplyAsync(() -> {
  9. if (user.getAge() > 5){
  10. int a = 1/0;
  11. }
  12. // 处理数据
  13. user.setName(user.getName() + "-改");
  14. log.info("打印-改:{}", user.getName());
  15. // 其他的业务逻辑。。。
  16. return user;
  17. }, myIoThreadPool)
  18. //处理异常方式1:返回默认值或者一个替代的 Future 对象,从而避免系统的崩溃或异常处理的问题。
  19. .exceptionally(throwable -> {
  20. //可以直接获取user
  21. System.out.println("异常了:" + user);
  22. //处理异常的方法……
  23. //1还可以进行业务处理……比如将异常数据存起来,然后导出……
  24. //2返回默认值,如:user、null
  25. //return user;
  26. //3抛出异常
  27. throw new RuntimeException(throwable.getMessage());
  28. })
  29. //处理异常方式2:类似exceptionally(不推荐)
  30. // .handle((userCs, throwable) -> {
  31. // System.out.println("handle:" + user);
  32. // if (throwable != null) {
  33. // // 处理异常
  34. // log.error("处理用户信息出现异常,用户名为:" + user.getName(), throwable);
  35. // // 返回原始数据
  36. // return userCs;
  37. // } else {
  38. // // 返回正常数据
  39. // return userCs;
  40. // }
  41. // })
  42. )
  43. .collect(Collectors.toList());
  44. //获取futures
  45. List<UserCs> endList = futures.stream()
  46. //阻塞所有线程
  47. .map(CompletableFuture::join)
  48. //取age大于10的用户
  49. .filter(user -> user.getAge() > 10)
  50. //按照age升序排序
  51. .sorted(Comparator.comparing(UserCs::getAge))
  52. .collect(Collectors.toList());
  53. log.info("打印:都执行完了。。。{}", endList);
  54. }

2.4、CompletableFuture的使用测试

1、推荐使用:test03、test05、test09、test10、test11

2、test07、test08就是test09的前身。


  • test01:获取当前电脑(服务器)的cpu核数

  • test02:线程池原始的使用(不推荐直接这样用)

  • test03:开启异步1 —— @Async

  • test04:开启异步2 —— CompletableFuture.runAsync()

  • test05:开启异步2的改造 —— CompletableFuture.runAsync() 和 supplyAsync() —— 阻塞所有异步方法,一起提交

      1. 相当于开了3个线程去执行三个不同的方法,然后执行完后一起提交。
  • test052:开启异步2的改造 —— 第一个任务执行完了,获取到返回值,给后面的执行,可以连写,也可以单写。 —— 阻塞线程:get、join

  • test06:CompletableFuture开启多线程——无返回值的

  • test07:CompletableFuture开启多线程——无返回值的——构建一个新List

      1. 1、相当于多线程执行任务,然后把结果插入到List
      2. 2、接收多线程的List必须是线程安全的,ArrayList线程不安全
      3. 线程安全的List —— CopyOnWriteArrayList 替代 ArrayList
  • test08:CompletableFuture开启多线程——无返回值的——构建一个新List——先有数据的情况(基本和test07是一个方法)

  • test09:CompletableFuture开启多线程——有返回值的,返回一个新的List——先有数据的情况——使用stream流的map

  • test10:CompletableFuture 异常处理。相当于是 test09的增强,处理异常

  • test11:CompletableFuture 异常处理:如果出现异常就舍弃任务。

      1. 1、想了一下,出现异常后的任务确实没有执行下去了,任务不往下执行,怎么会发现异常呢?
      2. 2、发现了异常任务也就完了。而且打印了异常,相当于返回了异常。
      3. 3、未发生异常的任务会执行完成。如果发生异常都返回空,最后舍弃空的,就得到任务执行成功的 CompletableFuture

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓所有方式↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓


  1. package com.cc.md;
  2. import com.cc.md.entity.UserCs;
  3. import com.cc.md.service.IAsyncService;
  4. import org.junit.jupiter.api.Test;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  9. import javax.annotation.Resource;
  10. import java.util.*;
  11. import java.util.concurrent.CompletableFuture;
  12. import java.util.concurrent.CopyOnWriteArrayList;
  13. import java.util.concurrent.ForkJoinPool;
  14. import java.util.concurrent.TimeUnit;
  15. import java.util.stream.Collectors;
  16. @SpringBootTest
  17. class Test01 {
  18. private static final Logger log = LoggerFactory.getLogger(Test01.class);
  19. @Resource(name = "myIoThreadPool")
  20. private ThreadPoolTaskExecutor myIoThreadPool;
  21. /**
  22. * 异步类
  23. */
  24. @Resource
  25. private IAsyncService asyncService;
  26. @Test
  27. void test01() {
  28. //获取当前jdk能调用的CPU个数(当前服务器的处理器个数)
  29. int i = Runtime.getRuntime().availableProcessors();
  30. System.out.println(i);
  31. }
  32. //线程池原始的使用
  33. @Test
  34. void test02() {
  35. try {
  36. for (int i = 0; i < 1000; i++) {
  37. int finalI = i;
  38. myIoThreadPool.submit(() -> {
  39. //第一批创建的线程数
  40. log.info("打印:{}", finalI);
  41. //模仿io流耗时
  42. try {
  43. Thread.sleep(5000);
  44. } catch (InterruptedException e) {
  45. throw new RuntimeException(e);
  46. }
  47. });
  48. }
  49. }catch(Exception e){
  50. throw new RuntimeException(e);
  51. }finally {
  52. myIoThreadPool.shutdown();
  53. }
  54. }
  55. //开启异步1 —— @Async
  56. @Test
  57. public void test03() throws Exception {
  58. log.info("打印:{}", "异步测试的-主方法1");
  59. asyncService.async1();
  60. asyncService.async2();
  61. //不会等待异步方法执行,直接返回前端数据
  62. log.info("打印:{}", "异步测试的-主方法2");
  63. }
  64. //开启异步2 —— CompletableFuture.runAsync()
  65. @Test
  66. public void test04() throws Exception {
  67. log.info("打印:{}", "异步测试的-主方法1");
  68. CompletableFuture.runAsync(() -> {
  69. log.info("打印:{}", "异步方法1!");
  70. //异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  71. this.async2("异步方法1!-end");
  72. }, myIoThreadPool);
  73. //不会等待异步方法执行,直接返回前端数据
  74. log.info("打印:{}", "异步测试的-主方法2");
  75. }
  76. //异步需要执行的方法,可以写在同一个类中。
  77. private void async2(String msg) {
  78. //模仿io流耗时
  79. try {
  80. Thread.sleep(5000);
  81. } catch (InterruptedException e) {
  82. throw new RuntimeException(e);
  83. }
  84. log.info("打印:{}", msg);
  85. }
  86. //开启异步2的改造 —— CompletableFuture.runAsync() 和 supplyAsync() —— 阻塞所有异步方法,一起提交
  87. //相当于开了3个线程去执行三个不同的方法,然后执行完后一起提交。
  88. @Test
  89. public void test05() throws Exception {
  90. log.info("打印:{}", "异步测试的-主方法1");
  91. //异步执行1
  92. CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
  93. log.info("打印:{}", "异步方法1!");
  94. //异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  95. this.async2("异步方法1-end");
  96. return "异步方法1";
  97. }, myIoThreadPool);
  98. //异步执行2
  99. CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
  100. log.info("打印:{}", "异步方法2!");
  101. //异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  102. this.async2("异步方法2-end");
  103. return "异步方法2";
  104. }, myIoThreadPool);
  105. //异步执行3,不用我们自己的线程池 —— 用的就是系统自带的 ForkJoinPool 线程池
  106. CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
  107. log.info("打印:{}", "异步方法3!");
  108. //异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  109. this.async2("异步方法3-end");
  110. });
  111. //阻塞所有异步方法,一起提交后才走下面的代码
  112. CompletableFuture.allOf(future1, future2, future3).join();
  113. log.info("打印:{}", "异步-阻塞-测试的-主方法2-end");
  114. }
  115. //开启异步2的改造 —— 第一个任务执行完了,获取到返回值,给后面的执行,可以连写,也可以单写。 —— 阻塞线程:get、join
  116. // CompletableFuture 的 get 和 join 方法区别:
  117. // get:①可以获取线程中的异常、②设置等待时间
  118. // join:推荐在 CompletableFuture 中使用 join() 方法,因为它没有受到 interrupt 的干扰,不需要捕获异常,也不需要强制类型转换。
  119. @Test
  120. public void test052() throws Exception {
  121. log.info("打印:{}", "异步测试的-主方法1");
  122. //异步执行1
  123. CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
  124. log.info("打印:{}", "异步方法1!");
  125. // 异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  126. String str = "异步方法1-end";
  127. this.async2(str);
  128. return str;
  129. }, myIoThreadPool);
  130. // 异步执行2 - 无返回值 —— 分开写的方式
  131. CompletableFuture<Void> future2 = future1.thenAccept(str1 -> {
  132. log.info("打印:{}", "异步方法2!");
  133. // 异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  134. this.async2(String.format("%s-加-异步方法2! - 无返回值 - ",str1));
  135. });
  136. // 异步执行3 - 有返回值 —— 分开写future1,连写future3方式
  137. CompletableFuture<String> future3 = future1.thenApply(str2 -> {
  138. log.info("打印:{}", "异步方法3!");
  139. // 异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
  140. this.async2(String.format("%s-加-异步方法3! - 有返回值 - ", str2));
  141. return "异步执行3 - 有返回值 ";
  142. //连写的方式。
  143. }).thenApply(str3 -> {
  144. String format = String.format("%s- end", str3);
  145. log.error("异步3然后应用 - {}", format);
  146. //返回后面的应用
  147. return format;
  148. });
  149. // 获取future3的返回值:
  150. //如果需要捕获异常、设置等待超时时间,则用get
  151. log.info("future3的返回值(不阻塞):{}", future3.get());
  152. // log.info("future3的返回值(不阻塞-设置等待时间,超时报错:TimeoutException):{}",
  153. // future3.get(2, TimeUnit.SECONDS));
  154. //推荐使用 join方法
  155. // log.info("future3的返回值(阻塞):{}", future3.join());
  156. //阻塞所有异步方法,一起提交后才走下面的代码
  157. CompletableFuture.allOf(future1, future2).join();
  158. log.info("打印:{}", "异步-阻塞-测试的-主方法2-end");
  159. }
  160. //CompletableFuture开启多线程——无返回值的
  161. @Test
  162. public void test06() throws Exception {
  163. List<CompletableFuture<Void>> futures = new ArrayList<>();
  164. //循环,模仿很多任务
  165. for (int i = 0; i < 1000; i++) {
  166. int finalI = i;
  167. CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  168. //第一批创建的线程数
  169. log.info("打印:{}", finalI);
  170. //模仿io流耗时
  171. try {
  172. Thread.sleep(5000);
  173. } catch (InterruptedException e) {
  174. throw new RuntimeException(e);
  175. }
  176. }, myIoThreadPool);
  177. futures.add(future);
  178. }
  179. //阻塞:多线程的任务执行。相当于多线程执行完了,再执行后面的代码
  180. //如果不阻塞,上面的相当于异步执行了。
  181. //阻塞方式1:可以获取返回的异常、设置等待时间
  182. // futures.forEach(future -> {
  183. // try {
  184. // future.get();
  185. // } catch (Exception e) {
  186. // throw new RuntimeException(e);
  187. // }
  188. // });
  189. //阻塞方式2(推荐)
  190. CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
  191. log.info("打印:都执行完了。。。");
  192. }
  193. //CompletableFuture开启多线程——无返回值的——构建一个新List
  194. //相当于多线程执行任务,然后把结果插入到List中
  195. //接收多线程的List必须是线程安全的,ArrayList线程不安全
  196. //线程安全的List —— CopyOnWriteArrayList 替代 ArrayList
  197. @Test
  198. public void test07() throws Exception {
  199. List<CompletableFuture<Void>> futures = new ArrayList<>();
  200. //存数据的List
  201. List<UserCs> addList = new CopyOnWriteArrayList<>();
  202. //循环,模仿很多任务
  203. for (int i = 0; i < 1000; i++) {
  204. int finalI = i;
  205. CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  206. log.info("打印:{}", finalI);
  207. UserCs userCs = new UserCs();
  208. userCs.setName(String.format("姓名-%s", finalI));
  209. userCs.setAge(finalI);
  210. addList.add(userCs);
  211. }, myIoThreadPool);
  212. futures.add(future);
  213. }
  214. //阻塞
  215. CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
  216. //返回新的List:endList,取age大于10的用户
  217. List<UserCs> endList = addList.stream()
  218. .filter(user -> user.getAge() > 10)
  219. //按照age升序排序
  220. .sorted(Comparator.comparing(UserCs::getAge))
  221. .collect(Collectors.toList());
  222. log.info("打印:都执行完了。。。{}", endList);
  223. }
  224. //CompletableFuture开启多线程——无返回值的——构建一个新List——先有数据的情况
  225. //用CopyOnWriteArrayList 替代 ArrayList接收
  226. @Test
  227. public void test08() throws Exception {
  228. //先获取数据,需要处理的任务。
  229. List<UserCs> users = this.getUserCs();
  230. //开启多线程
  231. List<CompletableFuture<Void>> futures = new ArrayList<>();
  232. //存数据的List
  233. List<UserCs> addList = new CopyOnWriteArrayList<>();
  234. //莫法处理任务
  235. users.forEach(user -> {
  236. CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  237. //添加数据
  238. user.setName(user.getName() + "-改");
  239. addList.add(user);
  240. log.info("打印-改:{}", user.getName());
  241. //其他的业务逻辑。。。
  242. }, myIoThreadPool);
  243. futures.add(future);
  244. });
  245. //阻塞
  246. CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
  247. //返回新的List:endList
  248. List<UserCs> endList = addList.stream()
  249. .filter(user -> user.getAge() > 10)
  250. //按照age升序排序
  251. .sorted(Comparator.comparing(UserCs::getAge))
  252. .collect(Collectors.toList());
  253. log.info("打印:都执行完了。。。{}", endList);
  254. }
  255. //CompletableFuture开启多线程——有返回值的,返回一个新的List——先有数据的情况——使用stream流的map
  256. //像这种,需要构建另一个数组的,相当于一个线程执行完了,会有返回值
  257. //使用stream流的map + CompletableFuture.supplyAsync()
  258. @Test
  259. public void test09() throws Exception {
  260. //先获取数据,需要处理的任务。
  261. List<UserCs> users = this.getUserCs();
  262. //莫法处理任务
  263. List<CompletableFuture<UserCs>> futures = users.stream()
  264. .map(user -> CompletableFuture.supplyAsync(() -> {
  265. // 处理数据
  266. user.setName(user.getName() + "-改");
  267. log.info("打印-改:{}", user.getName());
  268. // 其他的业务逻辑。。。
  269. return user;
  270. }, myIoThreadPool)).collect(Collectors.toList());
  271. //获取futures
  272. List<UserCs> endList = futures.stream()
  273. //阻塞所有线程
  274. .map(CompletableFuture::join)
  275. //取age大于10的用户
  276. .filter(user -> user.getAge() > 10)
  277. //按照age升序排序
  278. .sorted(Comparator.comparing(UserCs::getAge))
  279. .collect(Collectors.toList());
  280. log.info("打印:都执行完了。。。{}", endList);
  281. }
  282. //基础数据
  283. private List<UserCs> getUserCs() {
  284. List<UserCs> users = new ArrayList<>();
  285. for (int i = 0; i < 1000; i++) {
  286. UserCs userCs = new UserCs();
  287. userCs.setName(String.format("姓名-%s", i));
  288. userCs.setAge(i);
  289. users.add(userCs);
  290. }
  291. return users;
  292. }
  293. //CompletableFuture 异常处理
  294. @Test
  295. public void test10() throws Exception {
  296. //先获取数据,需要处理的任务。
  297. List<UserCs> users = this.getUserCs();
  298. //莫法处理任务
  299. List<CompletableFuture<UserCs>> futures = users.stream()
  300. .map(user -> CompletableFuture.supplyAsync(() -> {
  301. if (user.getAge() > 5){
  302. int a = 1/0;
  303. }
  304. // 处理数据
  305. user.setName(user.getName() + "-改");
  306. log.info("打印-改:{}", user.getName());
  307. // 其他的业务逻辑。。。
  308. return user;
  309. }, myIoThreadPool)
  310. //处理异常方式1:返回默认值或者一个替代的 Future 对象,从而避免系统的崩溃或异常处理的问题。
  311. .exceptionally(throwable -> {
  312. //可以直接获取user
  313. System.out.println("异常了:" + user);
  314. //处理异常的方法……
  315. //1还可以进行业务处理……比如将异常数据存起来,然后导出……
  316. //2返回默认值,如:user、null
  317. //return user;
  318. //3抛出异常
  319. throw new RuntimeException(throwable.getMessage());
  320. })
  321. //处理异常方式2:类似exceptionally(不推荐)
  322. // .handle((userCs, throwable) -> {
  323. // System.out.println("handle:" + user);
  324. // if (throwable != null) {
  325. // // 处理异常
  326. // log.error("处理用户信息出现异常,用户名为:" + user.getName(), throwable);
  327. // // 返回原始数据
  328. // return userCs;
  329. // } else {
  330. // // 返回正常数据
  331. // return userCs;
  332. // }
  333. // })
  334. )
  335. .collect(Collectors.toList());
  336. //获取futures
  337. List<UserCs> endList = futures.stream()
  338. //阻塞所有线程
  339. .map(CompletableFuture::join)
  340. //取age大于10的用户
  341. .filter(user -> user.getAge() > 10)
  342. //按照age升序排序
  343. .sorted(Comparator.comparing(UserCs::getAge))
  344. .collect(Collectors.toList());
  345. log.info("打印:都执行完了。。。{}", endList);
  346. }
  347. //CompletableFuture 异常处理:如果出现异常就舍弃任务。
  348. // 想了一下,出现异常后的任务确实没有执行下去了,任务不往下执行,怎么会发现异常呢?
  349. // 发现了异常任务也就完了。而且打印了异常,相当于返回了异常。
  350. // 未发生异常的任务会执行完成。如果发生异常都返回空,最后舍弃空的,就得到任务执行成功的 CompletableFuture
  351. @Test
  352. public void test11() {
  353. List<UserCs> users = getUserCs();
  354. List<CompletableFuture<UserCs>> futures = users.stream()
  355. .map(user -> CompletableFuture.supplyAsync(() -> {
  356. if (user.getAge() > 15) {
  357. int a = 1 / 0;
  358. }
  359. user.setName(user.getName() + "-改");
  360. log.info("打印-改:{}", user.getName());
  361. return user;
  362. }, myIoThreadPool)
  363. //处理异常
  364. .exceptionally(throwable -> {
  365. //其他处理异常的逻辑
  366. return null;
  367. })
  368. )
  369. //舍弃返回的对象是null的 CompletableFuture
  370. .filter(e -> Objects.nonNull(e.join())).collect(Collectors.toList());
  371. //获取futures
  372. List<UserCs> endList = futures.stream()
  373. //阻塞所有线程
  374. .map(CompletableFuture::join)
  375. //取age大于10的用户
  376. .filter(user -> user.getAge() > 10)
  377. //按照age升序排序
  378. .sorted(Comparator.comparing(UserCs::getAge))
  379. .collect(Collectors.toList());
  380. log.info("打印:都执行完了。。。{}", endList);
  381. }
  382. }

Java的CompletableFuture,Java的多线程开发的更多相关文章

  1. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  2. Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

    事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一 ...

  3. Java多线程开发系列之四:玩转多线程(线程的控制2)

    在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接 ...

  4. Java多线程开发系列之一:走进多线程

    对编程语言的基础知识:分支.选择.循环.面向对象等基本概念理解后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介 ...

  5. Java之多线程开发时多条件Condition接口的使用

    转:http://blog.csdn.net/a352193394/article/details/39454157 我们在多线程开发中,可能会出现这种情况.就是一个线程需要另外一个线程满足某某条件才 ...

  6. Java多线程开发技巧

    很多开发者谈到Java多线程开发,仅仅停留在new Thread(...).start()或直接使用Executor框架这个层面,对于线程的管理和控制却不够深入,通过读<Java并发编程实践&g ...

  7. Java网络多线程开发:java.io.EOFException

    Java网络多线程开发:java.io.EOFException 在实现韩顺平Java的多用户即使通信系统实战项目中: 对于客户端线程的停止,老韩是向服务器端发送一个消息对象,提示服务器端进行资源释放 ...

  8. Java基础高级二(多线程)

    1.进程和线程的区别:线程是轻量级的,本省不会持太多资源,需要的时候向进程申请 2.线程的状态:创建,可执行,执行中,等待,休眠,阻塞 3.线程状态之间的转换 4.线程API:Thread类,Runn ...

  9. 第九节:详细讲解Java中的泛型,多线程,网络编程

    前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...

  10. JAVA并发编程学习笔记------多线程调优

    1. 多线程场景下尽量使用并发容器代替同步容器 (如ConcurrentHashMap代替同步且基于散列的Map, 遍历操作为主要操作的情况下用CopyOnWriteArrayList代替同步的Lis ...

随机推荐

  1. PGF 概率生成函数 Probability generating function

    Probability Mass Function 离散随机变量的分布函数PMF 目录 随机结构举例 two classical combinatorial distributions PGF Pro ...

  2. 新版TinyCore Linux系统安装

    1.设置软件仓库源echo "https://mirrors.163.com/tinycorelinux">/opt/tcemirror 2.安装启动加载器及其依赖tce-l ...

  3. 易基因:PIWI/piRNA在人癌症中的表观遗传调控机制(DNA甲基化+m6A+组蛋白修饰)|综述

    大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因. 2023年03月07日,南华大学衡阳医学院李二毛团队在<Molecular Cancer>杂志发表了题为"The ...

  4. Solon v2.2.6 发布,助力信创国产化

    Solon 是一个高效的 Java 应用开发框架:更快.更小.更简单.它是一个有自己接口标准规范的开放生态,可为应用软件国产化提供支持,助力信创建设. 150来个生态插件,覆盖各种不同的应用开发场景: ...

  5. [ACM]快速排序模板

    思路 快排基本思路应该就是二分+递归,从两侧同时(实则先从右往左)往中间找,同时和参变量对比,发现位置颠倒后交换位置,然后通过二分将其一块一块的分割开,直到分割到一个元素位置,即完成了快排. 代码 # ...

  6. 存储论——经济订货批量的R实现

    存储论又称库存理论,是运筹学中发展较早的分支.早在 1915 年,哈李斯(F.Harris)针对银行货币的储备问题进行了详细的研究,建立了一个确定性的存贮费用模型,并求得了最佳批量公式.1934 年威 ...

  7. [Linux]U盘启动盘安装CentOS7系统(LiveGNOME版)

    1 准备:工具 U盘 容量:视CentOS具体版本需要而定.推荐4G+ UltraISO(软碟通) ISO制作工具 / U盘启动盘刻录工具 2 制作:U盘启动盘 step1 下载CentOS镜像 Ce ...

  8. LeeCode数组问题(二)

    LeeCode 977:有序数组的平方 题目描述: 给你一个按非递减顺序排列的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序. 标签:数组,首尾指针,最大值优先 时间复杂度: ...

  9. sql ytd 附python 实现方式

    ytd释义 YTD分析属于同比分析类,其特点在于对比汇总值,即从年初第一日值一直至今的值累加.作用在于分析企业中长期的经营绩效. 做法 假定: 有一张销量明细表 date 仓库 sku 销量 2020 ...

  10. Docker介绍下载安装、制作镜像及容器、做目录映射、做端口映射

    在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器.网络.内存及存储等,予以抽象.转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以 ...