GuavaFuture 有回撥函式的Future使用demo
阿新 • • 發佈:2020-10-16
谷歌的 guava 工具包和hutool 的工具包是目前比較全而且好用的java開發工具包可以避免我們重複造輪子,最近看了下Guava的ListenableFutrue可以線上程任務執行完成之後執行我們自己編寫的回撥函式,從而避免了get()方法的阻塞,感覺不錯,記錄一下。
本示例使用maven作為jar包管理工具,首先在pom檔案中引入guava工具包,程式碼如下:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId>
<version>xxx</version> </dependency>
PS: hutool 工具包引入示例:
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.2.0</version> </dependency>
首先講一下簡單的業務邏輯: 這是一個陽光明媚的早上,小明在學習程式設計,然後他想喝茶了。就跟管家說,你好Jenkins我想喝茶。然後就有兩個僕人去做事兒了,一個人洗茶杯一個人燒水,小明繼續學習。茶杯洗完了僕人會告訴小明然後把茶杯端過來,水燒開了僕人也告訴小明,把熱水壺拎過來。小明暫停學習然後去快樂地泡茶喝茶。然而,僕人可能在工作的過程中出岔子,其結果也會告知小明,小明只能放棄喝茶。以下是實現程式碼:
1 package com.vincent.fat.core.juc; 2 3 import cn.hutool.core.util.RandomUtil; 4 import com.google.common.util.concurrent.*; 5 import lombok.extern.slf4j.Slf4j; 6 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 7 import org.jetbrains.annotations.NotNull; 89 import java.util.concurrent.Callable; 10 import java.util.concurrent.ExecutorService; 11 import java.util.concurrent.Executors; 12 import java.util.concurrent.TimeUnit; 13 @Slf4j 14 public class GuavaFutureDemo { 15 public static void main(String[] args) { 16 Thread.currentThread().setName("主執行緒"); 17 ExecutorService executorService = Executors.newFixedThreadPool(10); 18 DrinkTeaJob drinkTeaJob=new DrinkTeaJob(executorService); 19 new Thread(drinkTeaJob,"喝茶執行緒").start(); 20 Callable<Boolean> hotWaterJob = new HotWaterJob(); 21 Callable<Boolean> cleanCapsJob = new CleanCapsJob(); 22 ListeningExecutorService gpool = MoreExecutors.listeningDecorator(executorService); 23 ListenableFuture<Boolean> hotFuture = gpool.submit(hotWaterJob); 24 ListenableFuture<Boolean> cleanWaterFuture = gpool.submit(cleanCapsJob); 25 Futures.addCallback(hotFuture, new FutureCallback<Boolean>() { 26 @Override 27 public void onSuccess(@NullableDecl Boolean result) { 28 if (result != null) { 29 drinkTeaJob.setWaterOk(result); 30 drinkTeaJob.setWaterJobDone(true); 31 } 32 } 33 @Override 34 public void onFailure(@NotNull Throwable t) { 35 drinkTeaJob.setWaterJobDone(true); 36 throw new RuntimeException(t.getMessage()); 37 } 38 },executorService); 39 Futures.addCallback(cleanWaterFuture, new FutureCallback<Boolean>() { 40 @Override 41 public void onSuccess(@NullableDecl Boolean result) { 42 if (result != null) { 43 drinkTeaJob.setCupsOk(result); 44 drinkTeaJob.setCupsJobDone(true); 45 } 46 } 47 @Override 48 public void onFailure(@NotNull Throwable t) { 49 drinkTeaJob.setCupsJobDone(true); 50 throw new RuntimeException(t.getMessage()); 51 } 52 },executorService); 53 log.warn("[{}]執行到最後一行程式碼",Thread.currentThread().getName()); 54 } 55 static class HotWaterJob implements Callable<Boolean>{ 56 /** 57 * Computes a result, or throws an exception if unable to do so. 58 * 59 * @return computed result 60 * @throws Exception if unable to compute a result 61 */ 62 @Override 63 public Boolean call() throws Exception { 64 TimeUnit.SECONDS.sleep(2); 65 if (RandomUtil.randomBoolean()){ 66 log.info("水已經燒好了..."); 67 return true; 68 } 69 else { 70 throw new RuntimeException("火滅了,水燒不開了。。。"); 71 } 72 } 73 } 74 static class CleanCapsJob implements Callable<Boolean>{ 75 /** 76 * Computes a result, or throws an exception if unable to do so. 77 * 78 * @return computed result 79 * @throws Exception if unable to compute a result 80 */ 81 @Override 82 public Boolean call() throws Exception { 83 TimeUnit.SECONDS.sleep(1); 84 boolean res; 85 if (res=RandomUtil.randomBoolean()){ 86 log.info("茶杯洗好了。。。。"); 87 } 88 else { 89 throw new RuntimeException("茶具摔壞了。。。"); 90 } 91 return true; 92 } 93 } 94 static class DrinkTeaJob implements Runnable{ 95 private boolean waterOk=false; 96 97 public boolean isWaterJobDone() { 98 return waterJobDone; 99 } 100 101 public void setWaterJobDone(boolean waterJobDone) { 102 this.waterJobDone = waterJobDone; 103 } 104 105 public boolean isCupsJobDone() { 106 return cupsJobDone; 107 } 108 109 public void setCupsJobDone(boolean cupsJobDone) { 110 this.cupsJobDone = cupsJobDone; 111 } 112 113 private boolean waterJobDone=false; 114 private boolean cupsJobDone=false; 115 private boolean cupsOk=false; 116 private final ExecutorService executorService; 117 DrinkTeaJob(ExecutorService executorService){ 118 this.executorService=executorService; 119 } 120 public void setWaterOk(boolean waterOk) { 121 this.waterOk = waterOk; 122 } 123 124 public void setCupsOk(boolean cupsOk) { 125 this.cupsOk = cupsOk; 126 } 127 128 private int gap=0; 129 /** 130 * When an object implementing interface <code>Runnable</code> is used 131 * to create a thread, starting the thread causes the object's 132 * <code>run</code> method to be called in that separately executing 133 * thread. 134 * <p> 135 * The general contract of the method <code>run</code> is that it may 136 * take any action whatsoever. 137 * 138 * @see Thread#run() 139 */ 140 @Override 141 public void run() { 142 while (!Thread.currentThread().isInterrupted()) 143 { 144 log.info("正在學習程式設計。。。"); 145 try{ 146 TimeUnit.MILLISECONDS.sleep(this.gap); 147 if (waterJobDone&&cupsJobDone) 148 { 149 this.drinkTea(); 150 } 151 } catch (InterruptedException interruptedException) { 152 log.error("喝茶執行緒被中斷了",interruptedException); 153 break; 154 } 155 this.gap+=500; 156 } 157 log.info("喝茶執行緒退出!!"); 158 this.executorService.shutdown(); 159 } 160 161 private void drinkTea() throws InterruptedException { 162 if (this.cupsOk&&this.waterOk) 163 { 164 log.info("泡茶,喝茶,蘇福~~~"); 165 }else { 166 log.warn("茶喝不成了,哭。。。。"); 167 } 168 TimeUnit.SECONDS.sleep(1); 169 Thread.currentThread().interrupt(); 170 } 171 } 172 }
程式執行結果1:
程式執行結果2: