Akka2使用探索6(Futures)——實現併發和異步

Future用來獲取某個併發操作的結果,這個結果可以同步(阻塞)或異步(非阻塞)的方式訪問。

 

執行上下文

Future 需要一個ExecutionContext, 它與java.util.concurrent.Executor 很相像. 如果你在作用域內有一個 ActorSystem , 它可以用system.dispatcher()作 ExecutionContext。你也可以用ExecutionContext 伴生對象提供的工廠方法來將 Executors 和 ExecutorServices 進行包裹, 或者甚至創建自己的實例.

//執行上下文可以自己指定線程池類型 ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()) Future的創建方法 Future<String> f1 = Futures.successful("f1", ec); Future<String> f2 = Futures.future(new Callable() { @Override Object call() { return "f2" } }, ec) Future<String> f3 = Futures.successful("f3", ActorSystem.create("test").dispatcher()); //使用actor的ask方法發送消息是也能創建一個Future Future f4 = akka.pattern.Patterns.ask(actor, "msg", 1000 * 60)
函數式 Future Akka 的 Future 有一些與Scala集合所使用的非常相似的 monadic 方法. 這使你可以構造出結果可以傳遞的‘管道’ 或 ‘數據流’.

map(對未來返回的結果進行處理)

讓Future以函數式風格工作的第一個方法是 map. 它需要一個函數來對Future的結果進行處理, 返回一個新的結果。map 方法的返回值是包含新結果的另一個 Future:

static void map() throws Exception { ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> f1 = Futures.successful("fof1o", ec); //map的作用是:對Futrue:f1的返回結果進行處理,返回一個新的結果 Future<Integer> f2 = f1.map(new Mapper<String, Integer>() { public Integer apply(String s) { return s.length(); } }); //這裏對未來f1返回的字符串計算其長度 對Future完成結果的處理方法 //System.out.println(Await.result(f2, Duration.create(5, "s"))); //阻塞式,當前線程在此等待 //下面是非阻塞式,異步返回 f2.onComplete(new OnComplete<Integer>() { @Override public void onComplete(Throwable failure, Integer success) { System.out.println("f2返回結果:" + success + ",failure:" + failure); } }); f2.onSuccess(new OnSuccess<Integer>() { @Override public void onSuccess(Integer result) { System.out.println("f2返回結果:" + result); } }); f2.onFailure(new OnFailure() { @Override public void onFailure(Throwable failure) { System.out.println("f2返回failure:" + failure); } }); }

 

flatMap(對多個Future返回的結果進行處理)

static void flatMap() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> f1 = Futures.successful("hello", ec); // Future<Integer> fr = f1.flatMap(new Mapper<String, Future&lt;Integer>&gt;() { public Future<Integer> apply(final String s) { return Futures.future(new Callable<Integer>() { public Integer call() { return s.length(); } }, ec); } }); // System.out.println(Await.result(fr, Duration.create(5, "s"))); //阻塞式 } //對兩個Future的結果處理 static void flatMap_concat2() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); final Future<String> f1 = Futures.successful("hello", ec); final Future<String> f2 = Futures.successful("world", ec); //如果要對多個Future的結果進行處理,需要用flatMap //本例中對f1和f2返回的結果用空格連接成“hello world” Future<String> fr = f1.flatMap(new Mapper<String, Future&lt;String>&gt;() { public Future<String> apply(final String s) { return f2.map(new Mapper<String, String>() { @Override public String apply(String v) { return s + " " + v; } }); } }); System.out.println(Await.result(fr, Duration.create(5, "s"))); //阻塞式 } //對三個Future的結果處理 static void flatMap_concat3() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); final Future<String> f1 = Futures.successful("How", ec); final Future<String> f2 = Futures.successful("are", ec); final Future<String> f3 = Futures.successful("you", ec); //如果要對多個Future的結果進行處理,需要用flatMap //本例中對f1、f2、f3返回的結果用空格連接成“How are you” Future<String> fr = f1.flatMap(new Mapper<String, Future&lt;String>&gt;() { public Future<String> apply(final String s) { return f2.flatMap(new Mapper<String, Future&lt;String>&gt;() { @Override public Future<String> apply(final String s2) { return f3.map(new Mapper<String, String>() { @Override public String apply(String s3) { return s + " " + s2 + " " + s3; } }); } }); } }); /*用java寫比較繁瑣,用scala的話就簡單多了 val future1 = for { a: String <- actor ? "How" // returns How b: String &lt;- actor ? "are" // returns "are" c: String &lt;- actor ? "you" // returns "you" } yield a + " " + b + "" + c*/ System.out.println(Await.result(fr, Duration.create(5, "s"))); //阻塞式 }

filter(對Future進行條件篩選)

static void filter() throws Exception { ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future&lt;String> f1 = Futures.successful("fof1o", ec); Future<String> f2 = Futures.successful("fo", ec); //map的作用是:對Futrue:f1的返回結果進行處理,返回一個新的結果 Future<String> fs = f1.filter(Filter.filterOf(new Function<String, Boolean>() { @Override public Boolean apply(String param) { return param.length() == 5; } })); System.out.println(Await.result(fs, Duration.create(5, "s"))); Future<String> ff = f2.filter(Filter.filterOf(new Function<String, Boolean>() { @Override public Boolean apply(String param) { return param.length() == 5; } })); //不匹配的話會拋scala.MatchError異常 System.out.println(Await.result(ff, Duration.create(5, "s"))); }

 


組合Futures

如果Future的數目較多,用flatMap組合的話代碼就過於複雜。可以使用sequence和traverse。

sequence(將 T[Future[A]] 轉換爲 Future[T[A]])

public static void sequence() throws Exception { //將 T[Future[A]] 轉換爲 Future[T[A]] //簡化了用flatMap來組合 final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); final Future<String> f1 = Futures.successful("How", ec); final Future<String> f2 = Futures.successful("are", ec); final Future<String> f3 = Futures.successful("you", ec); List<Future&lt;String>&gt; futureList = new ArrayList<Future&lt;String>&gt;(); futureList.add(f1); futureList.add(f2); futureList.add(f3); //這裏將List<Future&lt;String>&gt; 組合成一個Future:Future<Iterable&lt;String>&gt; Future<Iterable&lt;String>&gt; future = Futures.sequence(futureList, ec); Future<String> fr = future.map(new Mapper<Iterable&lt;String>, String&gt;() { @Override public String apply(Iterable<String> parameter) { String result = ""; for (String s : parameter) { result += s + " "; } return result; } }); System.out.println(Await.result(fr, Duration.create(5, "s"))); }


traverse(將 T[A] 轉換爲 Future[T[A]])

public static void traverse() throws Exception { //將 T[A] 轉換爲 Future[T[A]] final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Iterable<String> list = Arrays.asList("How", "are", "you"); //這裏將List<String> 組合成一個Future:Future<Iterable&lt;String>&gt; ,對list中的每個元素做加工處理 Future<Iterable&lt;String>&gt; future = Futures.traverse(list, new Function<String, Future&lt;String>&gt;() { @Override public Future<String> apply(final String param) { return Futures.future(new Callable<String>() { @Override public String call() throws Exception { return param.toUpperCase(); } }, ec); } }, ec); Future<String> fr = future.map(new Mapper<Iterable&lt;String>, String&gt;() { @Override public String apply(Iterable<String> parameter) { String result = ""; for (String s : parameter) { result += s + " "; } return result; } }); System.out.println(Await.result(fr, Duration.create(5, "s"))); }


fold(從一個初始值開始遞歸地對Future序列進行處理(它將sequence和map操作合併成一步了))

public static void fold() throws Exception { //fold從一個初始值開始遞歸地對Future序列進行處理(它將sequence和map操作合併成一步了) final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); final Future<String> f1 = Futures.successful("How", ec); final Future<String> f2 = Futures.successful("are", ec); final Future<String> f3 = Futures.successful("you", ec); List<Future&lt;String>&gt; futureList = new ArrayList<Future&lt;String>&gt;(); futureList.add(f1); futureList.add(f2); futureList.add(f3); //本例從初始值“Init”開始,遞歸地對futureList的返回值用"_"連接,返回“Init_How_are_you” Future<String> fr = Futures.fold("Init", futureList, new Function2<String, String, String>() { @Override public String apply(String arg1, String arg2) { System.out.println("arg1----" + arg1); //第一次爲Init,第二次爲Init_How ,第三次爲Init_How_are System.out.println("arg2----" + arg2); //第一次爲How ,第二次爲are 第三次爲you return arg1 + "_" + arg2; } }, ec); //如果futureList爲空列表,則返回初始值“Init” System.out.println(Await.result(fr, Duration.create(5, "s"))); //結果爲Init_How_are_you }
reduce(如果不想從給定的初始值開始遞歸,而想從future序列的第一個開始,則用reduce(它將sequence和map合併成一步了))
public static void reduce() throws Exception { //如果不想從給定的初始值開始遞歸,而想從future序列的第一個開始,則用reduce(它將sequence和map合併成一步了) final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); final Future<String> f1 = Futures.successful("How", ec); final Future<String> f2 = Futures.successful("are", ec); final Future<String> f3 = Futures.successful("you", ec); List<Future&lt;String>&gt; futureList = new ArrayList<Future&lt;String>&gt;(); futureList.add(f1); futureList.add(f2); futureList.add(f3); //本例從初始值“How”開始,遞歸地對futureList的返回值用"_"連接,返回“How_are_you” Future<String> fr = Futures.reduce(futureList, new Function2<String, String, String>() { @Override public String apply(String arg1, String arg2) { System.out.println("arg1----" + arg1); //第一次爲How ,第二次爲How_are System.out.println("arg2----" + arg2); //第一次爲are ,第二次爲you return arg1 + "_" + arg2; } }, ec); //如果futureList爲空列表,則返回初始值“Init” System.out.println(Await.result(fr, Duration.create(5, "s"))); //結果爲Init_How_are_you }

 

andThen(由於回調的執行是無序的,而且可能是併發執行的, 當你需要一組有序操作的時候需要一些技巧。)

public static void andThen() throws Exception { //如果要對Future的結果分多次依次處理,需要使用andThen final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> future = Futures.successful("hello", ec).andThen(new OnComplete<String>() { @Override public void onComplete(Throwable failure, String success) { System.out.println("先收到:" + success); } }).andThen(new OnComplete<String>() { @Override public void onComplete(Throwable failure, String success) { System.out.println("又收到:" + success); } }).andThen(new OnSuccess<Either&lt;Throwable, String>&gt;() { @Override public void onSuccess(Either<Throwable, String> result) { System.out.println("收到onSuccess:" + result); } }); }


fallbackTo(將兩個 Futures 合併成一個新的 Future, 如果第一個Future失敗了,它將持有第二個 Future 的成功值)

public static void fallbackTo() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> f1 = Futures.failed(new RuntimeException("ex1"), ec); Future<String> f2 = Futures.failed(new RuntimeException("ex2"), ec); Future<String> f3 = Futures.successful("ok", ec); //fallbackTo 將兩個 Futures 合併成一個新的 Future, 如果第一個Future失敗了,它將持有第二個 Future 的成功值 Future<String> fr = f1.fallbackTo(f2).fallbackTo(f3); System.out.println(Await.result(fr, Duration.create(5, "s"))); }

 

zip(操作將兩個 Futures 組合壓縮成一個新的Future,返回的新的Future持hold一個tuple實例,它包含二者成功的結果)

public static void zip() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> f1 = Futures.future(new Callable<String>() { @Override public String call() throws Exception { System.out.println("f1---" + Thread.currentThread().getName()); Thread.sleep(1000 * 10); return "hello"; } }, ec); Future<String> f2 = Futures.future(new Callable<String>() { @Override public String call() throws Exception { System.out.println("f2---" + Thread.currentThread().getName()); Thread.sleep(1000 * 5); return "world"; } }, ec); //zip操作將兩個 Futures 組合壓縮成一個新的Future,返回的新的Future持hold一個tuple實例,它包含二者成功的結果 Future<String> fr = f1.zip(f2).map(new Mapper<Tuple2&lt;String, String>, String&gt;() { @Override public String apply(Tuple2<String, String> ziped) { System.out.println("zip---" + Thread.currentThread().getName()); return ziped._1() + " " + ziped._2(); //f1和f2的返回結果包含在zipped對象中 } }); System.out.println("主線程----" + Thread.currentThread().getName()); System.out.println(Await.result(fr, Duration.create(15, "s"))); } public static void zip2() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); Future<String> f1 = Futures.successful("hello", ec); Future<String> f2 = Futures.future(new Callable<String>() { @Override public String call() throws Exception { System.out.println("f2---" + Thread.currentThread().getName()); Thread.sleep(1000 * 10); return (1 / 0) + ""; } }, ec); //zip操作將兩個 Futures 組合壓縮成一個新的Future,返回的新的Future持hold一個tuple實例,它包含二者成功的結果 Future<String> fr = f1.zip(f2).map(new Mapper<Tuple2&lt;String, String>, String&gt;() { @Override public String apply(Tuple2<String, String> ziped) { System.out.println("zip----" + Thread.currentThread().getName()); return ziped._1() + " " + ziped._2(); //f1和f2的返回結果包含在zipped對象中 } }); System.out.println("主線程----" + Thread.currentThread().getName()); System.out.println(Await.result(fr, Duration.create(15, "s"))); }

 

recover(對Future的異常進行處理,相當於try..catch中對捕獲異常後的處理)

public static void recover() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); //recover對Future的異常進行處理,相當於try..catch中對捕獲異常後的處理 Future<Integer> future = Futures.future(new Callable<Integer>() { public Integer call() { return 1 / 0; } }, ec).recover(new Recover<Integer>() { public Integer recover(Throwable problem) throws Throwable { System.out.println("捕獲到異常:" + problem); // if (problem instanceof RuntimeException) { // return 0; // } else { // throw problem; // } return -2; //這裏捕獲到異常後直接返回新值了,並沒有再拋出異常,所以後面的recover不會再收到異常 } }).recover(new Recover<Integer>() { public Integer recover(Throwable problem) throws Throwable { System.out.println("捕獲到異常:" + problem); if (problem instanceof ArithmeticException) { //捕獲異常並處理,捕獲到後,後面得到的result將會是-1 return -1; } else { throw problem; } } }); int result = Await.result(future, Duration.create(1, TimeUnit.SECONDS)); System.out.println("result----" + result); }

 

recoverWith(和recover很類似,只是捕獲到異常後返回Future,使其能夠異步併發處理)

public static void recoverWith() throws Exception { final ExecutionContextExecutorService ec = ExecutionContexts.fromExecutorService(Executors.newCachedThreadPool()); //recoverWith和recover很類似,只是捕獲到異常後返回Future,使其能夠異步併發處理 Future<Integer> future = Futures.future(new Callable<Integer>() { public Integer call() { return 1 / 0; } }, ec).recoverWith(new Recover<Future&lt;Integer>&gt;() { @Override public Future<Integer> recover(Throwable failure) throws Throwable { if (failure instanceof ArithmeticException) { return Futures.future(new Callable<Integer>() { @Override public Integer call() throws Exception { return 0; } }, ec); } else throw failure; } }); int result = Await.result(future, Duration.create(1, TimeUnit.SECONDS)); System.out.println("result----" + result); }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章