生産消費者模式
貌似也是阻塞的問題
花了一些時間終于弄明白這個鳥東東,以前還以為是不複雜的一個東西的,以前一直以為和觀察者模式差不多(其實也是差不多的,呵呵),生産消費者模式應該是可以通過觀察者模式來實作的,對于在什麼環境下使用現在想的還不是特别清楚,主要是在實際中還沒使用過這個。
需要使用到同步,以及線程,屬于多并發行列,和觀察者模式的差異也就在于此吧,是以實作起來也主要在這裡的差異。
在實際的軟體開發過程中,經常會碰到如下場景:某個子產品負責産生資料,這些資料由另一個子產品來負責處理(此處的子產品是廣義的,可以是類、函數、線程、程序等)。産生資料的子產品,就形象地稱為生産者;而處理資料的子產品,就稱為消費者。
單單抽象出生産者和消費者,還夠不上是生産者/消費者模式。該模式還需要有一個緩沖區處于生産者和消費者之間,作為一個中介。生産者把資料放入緩沖區,而消費者從緩沖區取出資料
◇解耦
假設生産者和消費者分别是兩個類。如果讓生産者直接調用消費者的某個方法,那麼生産者對于消費者就會産生依賴(也就是耦合)。将來如果消費者的代碼發生變化,可能會影響到生産者。而如果兩者都依賴于某個緩沖區,兩者之間不直接依賴,耦合也就相應降低了。
◇支援并發(concurrency)
生産者直接調用消費者的某個方法,還有另一個弊端。由于函數調用是同步的(或者叫阻塞的),在消費者的方法沒有傳回之前,生産者隻好一直等在那邊。萬一消費者處理資料很慢,生産者就會白白糟蹋大好時光。
使用了生産者/消費者模式之後,生産者和消費者可以是兩個獨立的并發主體(常見并發類型有程序和線程兩種,後面的文章會講兩種并發類型下的應用)。生産者把制造出來的資料往緩沖區一丢,就可以再去生産下一個資料。基本上不用依賴消費者的處理速度。其實當初這個模式,主要就是用來處理并發問題的。
◇支援忙閑不均
緩沖區還有另一個好處。如果制造資料的速度時快時慢,緩沖區的好處就展現出來了。當資料制造快的時候,消費者來不及處理,未處理的資料可以暫時存在緩沖區中。等生産者的制造速度慢下來,消費者再慢慢處理掉。
用了兩種方式實作了一下這個模式,主要參考了網上的一些例子才弄明白,這裡對隊列的實作有很多種方法,需要和具體的應用相結合吧,隊列緩沖區很簡單,現在已有大量的實作,缺點是在性能上面(記憶體配置設定的開銷和同步/互斥的開銷),下面的實作都是這種方式;環形緩沖區(減少了記憶體配置設定的開銷),雙緩沖區(減少了同步/互斥的開銷)。
第一個例子是使用的信号量的東東,沒有執行具體的東西,隻是實作了這個例子,要做複雜的業務邏輯的話需要自己在某些方法内去具體實作
代碼如下:
消費者:
生産者:
隊列(使用了信号量,采用synchronized進行同步,采用lock進行同步會出錯,或許是還不知道實作的方法):
測試代碼:
運作結果:
第二種發放使用java.util.concurrent.BlockingQueue類來重寫的隊列那個類,使用這個方法比較簡單,并且性能上也沒有什麼問題。
這是jdk裡面的例子
jdk1.5以上的一個實作,使用了Lock以及條件變量等東西