欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

簡(jiǎn)單講解Java的Future編程模式

 更新時(shí)間:2015年11月08日 08:55:59   作者:WitsMakeMen  
這篇文章主要介紹了Java的Future編程模式,包括對(duì)異步和并發(fā)的一些設(shè)計(jì)思維,需要的朋友可以參考下

用過(guò)Java并發(fā)包的朋友或許對(duì)Future (interface) 已經(jīng)比較熟悉了,其實(shí)Future 本身是一種被廣泛運(yùn)用的并發(fā)設(shè)計(jì)模式,可在很大程度上簡(jiǎn)化需要數(shù)據(jù)流同步的并發(fā)應(yīng)用開(kāi)發(fā)。在一些領(lǐng)域語(yǔ)言(如Alice ML )中甚至直接于語(yǔ)法層面支持Future。

這里就以java.util.concurrent.Future 為例簡(jiǎn)單說(shuō)一下Future的具體工作方式。Future對(duì)象本身可以看作是一個(gè)顯式的引用,一個(gè)對(duì)異步處理結(jié)果的引用。由于其異步性質(zhì),在創(chuàng)建之初,它所引用的對(duì)象可能還并不可用(比如尚在運(yùn)算中,網(wǎng)絡(luò)傳輸中或等待中)。這時(shí),得到Future的程序流程如果并不急于使用Future所引用的對(duì)象,那么它可以做其它任何想做的事兒,當(dāng)流程進(jìn)行到需要Future背后引用的對(duì)象時(shí),可能有兩種情況:

希望能看到這個(gè)對(duì)象可用,并完成一些相關(guān)的后續(xù)流程。如果實(shí)在不可用,也可以進(jìn)入其它分支流程。
“沒(méi)有你我的人生就會(huì)失去意義,所以就算??菔癄€,我也要等到你?!保ó?dāng)然,如果實(shí)在沒(méi)有毅力枯等下去,設(shè)一個(gè)超時(shí)也是可以理解的)
對(duì)于前一種情況,可以通過(guò)調(diào)用Future.isDone()判斷引用的對(duì)象是否就緒,并采取不同的處理;而后一種情況則只需調(diào)用get()或
get(long timeout, TimeUnit unit)通過(guò)同步阻塞方式等待對(duì)象就緒。實(shí)際運(yùn)行期是阻塞還是立即返回就取決于get()的調(diào)用時(shí)機(jī)和對(duì)象就緒的先后了。

簡(jiǎn)單而言,F(xiàn)uture模式可以在連續(xù)流程中滿(mǎn)足數(shù)據(jù)驅(qū)動(dòng)的并發(fā)需求,既獲得了并發(fā)執(zhí)行的性能提升,又不失連續(xù)流程的簡(jiǎn)潔優(yōu)雅。

與其它并發(fā)設(shè)計(jì)模式的對(duì)比
除了Future外,其它比較常見(jiàn)的并發(fā)設(shè)計(jì)模式還包括“回調(diào)驅(qū)動(dòng)(多線程環(huán)境下)”、“消息/事件驅(qū)動(dòng)(Actor模型中)”等。

回調(diào)是最常見(jiàn)的異步并發(fā)模式,它有即時(shí)性高、接口設(shè)計(jì)簡(jiǎn)單等有點(diǎn)。但相對(duì)于Future,其缺點(diǎn)也非常明顯。首先,多線程環(huán)境下的回調(diào)一般是在觸發(fā)回調(diào)的模塊線程中執(zhí)行的,這就意味著編寫(xiě)回調(diào)方法時(shí)通常必須考慮線程互斥問(wèn)題;其次,回調(diào)方式接口的提供者在本模塊的線程中執(zhí)行用戶(hù)應(yīng)用的回調(diào)也是相對(duì)不安全的,因?yàn)槟銦o(wú)法確定它會(huì)花費(fèi)多長(zhǎng)時(shí)間或出現(xiàn)什么異常,從而可能間接導(dǎo)致本模塊的即時(shí)性和可靠性受影響;再者,使用回調(diào)接口不利于順序流程的開(kāi)發(fā),因?yàn)榛卣{(diào)方法的執(zhí)行是孤立的,要與正常流程匯合是比較困難的。因此回調(diào)接口適合于在回調(diào)中只需要完成簡(jiǎn)單任務(wù),并且不必與其它流程匯合的場(chǎng)景。

上述這些回調(diào)模式的缺點(diǎn)恰恰正是Future的長(zhǎng)項(xiàng)。由于Future的使用是將異步的數(shù)據(jù)驅(qū)動(dòng)天然的融入順序流程中,因此你完全不必考慮線程互斥問(wèn)題,F(xiàn)uture甚至可以在單線程的程序模型(例如協(xié)程)中實(shí)現(xiàn)(參見(jiàn)下文將要提到的“Lazy Future”)。另一方面,提供Future接口的模塊完全不必?fù)?dān)心像回調(diào)接口那樣的可靠性問(wèn)題和可能對(duì)本模塊的即時(shí)性影響。

另一類(lèi)常見(jiàn)的并發(fā)設(shè)計(jì)模式是“消息(事件)驅(qū)動(dòng)”,它一般運(yùn)用在Actor模型中:服務(wù)請(qǐng)求者向服務(wù)提供者發(fā)送消息,然后繼續(xù)進(jìn)行后續(xù)不依賴(lài)服務(wù)處理結(jié)果的任務(wù),在需要依賴(lài)結(jié)果前終止當(dāng)前流程并記錄狀態(tài);在等到回應(yīng)消息后根據(jù)記錄的狀態(tài)觸發(fā)后續(xù)流程。這種基于狀態(tài)機(jī)的并發(fā)控制雖然比回調(diào)更適合于有延續(xù)性的順序流程,但開(kāi)發(fā)者卻不得不將連續(xù)流程按照異步服務(wù)的調(diào)用切斷為多個(gè)按狀態(tài)區(qū)分的子流程,這樣又人為的增加了開(kāi)發(fā)的復(fù)雜性。運(yùn)用Future模式可以避免這個(gè)問(wèn)題,不必為了異步調(diào)用而打碎連續(xù)的流程。但是有一點(diǎn)應(yīng)當(dāng)特別注意:Future.get()方法可能會(huì)阻塞線程的執(zhí)行,所以它通常無(wú)法直接融入常規(guī)的Actor模型中。(基于協(xié)程的Actor模型可以較好的解決這個(gè)沖突)

Future的靈活性還體現(xiàn)在其同步和異步的自由取舍,開(kāi)發(fā)者可以根據(jù)流程的需要自由決定是否需要等待[Future.isDone()],何時(shí)等待[Future.get()],等待多久[Future.get(timeout)]。比如可以根據(jù)數(shù)據(jù)是否就緒而決定要不要借這個(gè)空檔完成點(diǎn)其它任務(wù),這對(duì)于實(shí)現(xiàn)“異步分支預(yù)測(cè)”機(jī)制是相當(dāng)方便的。

Future的衍生
除了上面提到的基礎(chǔ)形態(tài)之外,F(xiàn)uture還有豐富的衍生變化,這里就列舉幾個(gè)常見(jiàn)的。

Lazy Future
與一般的Future不同,Lazy Future在創(chuàng)建之初不會(huì)主動(dòng)開(kāi)始準(zhǔn)備引用的對(duì)象,而是等到請(qǐng)求對(duì)象時(shí)才開(kāi)始相應(yīng)的工作。因此,Lazy Future本身并不是為了實(shí)現(xiàn)并發(fā),而是以節(jié)約不必要的運(yùn)算資源為出發(fā)點(diǎn),效果上與Lambda/Closure類(lèi)似。例如設(shè)計(jì)某些API時(shí),你可能需要返回一組信息,而其中某些信息的計(jì)算可能會(huì)耗費(fèi)可觀的資源。但調(diào)用者不一定都關(guān)心所有的這些信息,因此將那些需要耗費(fèi)較多資源的對(duì)象以Lazy Future的形式提供,可以在調(diào)用者不需要用到特定的信息時(shí)節(jié)省資源。

另外Lazy Future也可以用于避免過(guò)早的獲取或鎖定資源而產(chǎn)生的不必要的互斥。

Promise
Promise可以看作是Future的一個(gè)特殊分支,常見(jiàn)的Future一般是由服務(wù)調(diào)用者直接觸發(fā)異步處理流程,比如調(diào)用服務(wù)時(shí)立即觸發(fā)處理或 Lazy Future的取值時(shí)觸發(fā)處理。但Promise則用于顯式表示那些異步流程并不直接由服務(wù)調(diào)用者觸發(fā)的情景。例如Future接口的定時(shí)控制,其異步流程不是由調(diào)用者,而是由系統(tǒng)時(shí)鐘觸發(fā),再比如淘寶的分布式訂閱框架提供的Future式訂閱接口,其等待數(shù)據(jù)的可用性不是由訂閱者決定,而在于發(fā)布者何時(shí)發(fā)布或更新數(shù)據(jù)。因此,相對(duì)于標(biāo)準(zhǔn)的Future,Promise接口一般會(huì)多出一個(gè)set()或fulfill()接口。

可復(fù)用的Future
常規(guī)的Future是一次性的,也就是說(shuō)當(dāng)你獲得了異步的處理結(jié)果后,F(xiàn)uture對(duì)象本身就失去意義了。但經(jīng)過(guò)特殊設(shè)計(jì)的Future也可以實(shí)現(xiàn)復(fù)用,這對(duì)于可多次變更的數(shù)據(jù)顯得非常有用。例如前面提到的淘寶分布式訂閱框架所提供的Future式接口,它允許多次調(diào)用waitNext()方法(相當(dāng)于Future.get()),每次調(diào)用時(shí)是否阻塞取決于在上次調(diào)用后是否又有數(shù)據(jù)發(fā)布,如果尚無(wú)更新,則阻塞直到下一次的數(shù)據(jù)發(fā)布。這樣設(shè)計(jì)的好處是,接口的使用者可以在其任何合適的時(shí)機(jī),或者直接簡(jiǎn)單的在獨(dú)立的線程中通過(guò)一個(gè)無(wú)限循環(huán)響應(yīng)訂閱數(shù)據(jù)的變化,同時(shí)還可兼顧其它定時(shí)任務(wù),甚至同時(shí)等待多個(gè)Future。簡(jiǎn)化的例子如下:

for (;;) {
 schedule = getNextScheduledTaskTime();
 while(schedule > now()) {
  try {
   data = subscription.waitNext(schedule - now());
   processData(data);
  } catch(Exception e) {...}
 }
 doScheduledTask();
}

Future的使用
首先列舉一段Thinking in Java中的代碼,這是出在并發(fā)中的Callable使用的一個(gè)例子,代碼,如下:

//: concurrency/CallableDemo.java
import java.util.concurrent.*;
import java.util.*;

class TaskWithResult implements Callable<String> {
 private int id;
 public TaskWithResult(int id) {
  this.id = id;
 }
 public String call() {
  return "result of TaskWithResult " + id;
 }
}

public class CallableDemo {
 public static void main(String[] args) {
  ExecutorService exec = Executors.newCachedThreadPool();
  ArrayList<Future<String>> results =
   new ArrayList<Future<String>>();
  for(int i = 0; i < 10; i++)
   results.add(exec.submit(new TaskWithResult(i)));
  for(Future<String> fs : results)
   try {
    // get() blocks until completion:
    System.out.println(fs.get());
   } catch(InterruptedException e) {
    System.out.println(e);
    return;
   } catch(ExecutionException e) {
    System.out.println(e);
   } finally {
    exec.shutdown();
   }
 }
} /* Output:
result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 2
result of TaskWithResult 3
result of TaskWithResult 4
result of TaskWithResult 5
result of TaskWithResult 6
result of TaskWithResult 7
result of TaskWithResult 8
result of TaskWithResult 9
*///:~ 

解釋一下Future的使用過(guò)程,首先ExecutorService對(duì)象exec調(diào)用submit()方法會(huì)產(chǎn)生Future對(duì)象,他用Callable返回結(jié)果的特定類(lèi)型進(jìn)行了參數(shù)化。你可以使用isDone()方法來(lái)查詢(xún)Future是否已經(jīng)完成。當(dāng)任務(wù)完成時(shí),他具有一個(gè)結(jié)果,你可以調(diào)用get()方法獲取結(jié)果。你也可以不用isDone()進(jìn)行檢查直接調(diào)用get(),在這種情況下,get()將會(huì)阻塞知道結(jié)果準(zhǔn)備就緒。你可以在調(diào)用具有超時(shí)的get()函數(shù),或者先調(diào)用isDone()來(lái)查看任務(wù)是否完成,然后再調(diào)用get()。

相關(guān)文章

  • 詳解Java的call by value和call by reference

    詳解Java的call by value和call by reference

    在本篇文章里小編給大家總結(jié)了關(guān)于Java的call by value和call by reference的相關(guān)用法和知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)下。
    2019-03-03
  • Java中的LinkedHashSet解析

    Java中的LinkedHashSet解析

    這篇文章主要介紹了Java中的LinkedHashSet解析,與HashSet不同的是,LinkedHashSet在內(nèi)部使用了一個(gè)雙向鏈表來(lái)維護(hù)元素的順序,因此它可以保持元素的插入順序,這使得LinkedHashSet在需要保持元素順序的場(chǎng)景下非常有用,需要的朋友可以參考下
    2023-11-11
  • springboot項(xiàng)目配置多個(gè)kafka的示例代碼

    springboot項(xiàng)目配置多個(gè)kafka的示例代碼

    這篇文章主要介紹了springboot項(xiàng)目配置多個(gè)kafka,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • MybatisPlusInterceptor實(shí)現(xiàn)sql攔截器超詳細(xì)教程

    MybatisPlusInterceptor實(shí)現(xiàn)sql攔截器超詳細(xì)教程

    這篇文章主要給大家介紹了關(guān)于MybatisPlusInterceptor實(shí)現(xiàn)sql攔截器超詳細(xì)教程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • 解決spring cloud服務(wù)啟動(dòng)之后回到命令行會(huì)自動(dòng)掛掉問(wèn)題

    解決spring cloud服務(wù)啟動(dòng)之后回到命令行會(huì)自動(dòng)掛掉問(wèn)題

    這篇文章主要介紹了解決spring cloud服務(wù)啟動(dòng)之后回到命令行會(huì)自動(dòng)掛掉問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 一篇文章帶你了解Java泛型的super和extends

    一篇文章帶你了解Java泛型的super和extends

    這篇文章主要介紹了Java泛型extends及super區(qū)別實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-08-08
  • 使用SpringMVC接收文件流上傳和表單參數(shù)

    使用SpringMVC接收文件流上傳和表單參數(shù)

    這篇文章主要介紹了使用SpringMVC接收文件流上傳和表單參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • springboot 整合EhCache實(shí)現(xiàn)單服務(wù)緩存的操作方法

    springboot 整合EhCache實(shí)現(xiàn)單服務(wù)緩存的操作方法

    這篇文章主要介紹了springboot 整合EhCache實(shí)現(xiàn)單服務(wù)緩存的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 解析java中super的用法分析

    解析java中super的用法分析

    本篇文章是對(duì)java中super的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • java處理異常Exception的方法總結(jié)

    java處理異常Exception的方法總結(jié)

    在Java中處理異常并不是一個(gè)簡(jiǎn)單的事情,不僅僅初學(xué)者很難理解,即使一些有經(jīng)驗(yàn)的開(kāi)發(fā)者也需要花費(fèi)很多時(shí)間,本文為大家整理了java處理異常Exception的一些常用方法,希望對(duì)大家有所幫助
    2023-09-09

最新評(píng)論