日常开发中,我们都会用到线程池,一般会用execute()和submit()方法提交任务。但是当你用过CompletableFuture之后,就会发现以前的线程池处理任务有多难用,功能有多简陋,CompletableFuture又是多么简洁优雅。
要知道CompletableFuture已经随着Java8发布7年了,还没有过它就有点说不过去了。
一、线程池处理任务和CompletableFuture处理任务
1.1、使用线程池处理任务
1 /** 2 * 1. 使用线程池处理任务 3 */ 4 @Test 5 public void test1() throws ExecutionException, InterruptedException { 6 // 1. 创建线程池 7 ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); 8 List<Integer> list = Arrays.asList(1, 2, 3); 9 10 for (Integer key : list) { 11 // 2. 提交任务 12 Future<String> future = executorService.submit(() -> { 13 // 睡眠一秒,模仿处理过程 14 Thread.sleep(1000L); 15 return "结果" + key; 16 }); 17 // 3. 获取结果 18 System.out.println(future.get()); 19 } 20 executorService.shutdown(); 21 }
输出结果:
结果1 结果2 结果3
这里能够发现两个问题:
- 获取结果时,调用的future.get()方法,会阻塞当前线程,直到返回结果,大大降低性能
- 有一半的代码在写怎么使用线程,其实我们不应该关心怎么使用线程,更应该关注任务的处理
有没有具体的优化方案呢?当然有了,请出来我们今天的主角CompletableFuture
1.2、使用CompletableFuture处理任务
1 /** 2 * 使用CompletableFuture重构任务处理 3 */ 4 @Test 5 public void test2() { 6 // 1. 创建线程池 7 ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); 8 9 List<Integer> list = Arrays.asList(1, 2, 3); 10 for (Integer key : list) { 11 // 2. 提交任务 12 CompletableFuture.supplyAsync(() -> { 13 // 睡眠一秒,模仿处理过程 14 try { 15 Thread.sleep(1000L); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 return "结果" + key; 20 }, executorService).whenCompleteAsync((result, exception) -> { 21 // 3. 获取结果 22 System.out.println(result); 23 }); 24 } 25 26 executorService.shutdown(); 27 // 由于whenCompleteAsync获取结果的方法是异步的,所以要阻塞当前线程才能输出结果 28 try { 29 Thread.sleep(2000L); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 }
输出结果:
结果2 结果3 结果1
可以看到是ComparableFutrue是通过supplyAsync方法进行异步执行任务的。
=============================================================
可是上面的任务执行还是有一些问题的,需要阻塞当前线程输出结果,但是我们并不能确定线程的执行结束时间。也就无法准确设置线程阻塞时间,这样子就会导致最后执行的结果不对。
我们可以通过join进行优化一下:异步任务完成时统一返回结果值
1 public void test2() { 2 // 1. 创建线程池 3 ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); 4 5 List<Integer> list = Arrays.asList(1, 2, 3); 6 List<String> joinResult = new ArrayList<>(); 7 for (Integer key : list) { 8 // 2. 提交任务 9 String taskResult = CompletableFuture.supplyAsync(() -> { 10 // 睡眠一秒,模仿处理过程 11 try { 12 Thread.sleep(1000L); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 return "结果" + key; 17 // 完成时返回结果值 18 }, executorService).join(); 19 joinResult.add(taskResult); 20 } 21 executorService.shutdown(); 22 // 3、打印结果 23 joinResult.forEach(System.out::println); 24 }
标签:结果,简单,new,线程,使用,CompletableFuture,executorService,ThreadPoolExecutor From: https://www.cnblogs.com/zhangzhixi/p/16624757.html