完全理解Java中生產(chǎn)者和消費(fèi)者模型.docx_第1頁
完全理解Java中生產(chǎn)者和消費(fèi)者模型.docx_第2頁
完全理解Java中生產(chǎn)者和消費(fèi)者模型.docx_第3頁
完全理解Java中生產(chǎn)者和消費(fèi)者模型.docx_第4頁
全文預(yù)覽已結(jié)束

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

生產(chǎn)者與消費(fèi)者模型 在平時(shí)的編程中,經(jīng)常遇到一個(gè)線程要產(chǎn)生數(shù)據(jù),而另一個(gè)線程要處理產(chǎn)生出來的數(shù)據(jù),這其實(shí)就是生產(chǎn)者和消費(fèi)者的關(guān)系。生產(chǎn)者在產(chǎn)生數(shù)據(jù)后可以直接調(diào)用消費(fèi)者處理數(shù)據(jù);也可以把數(shù)據(jù)放在一個(gè)緩沖區(qū)中,讓消費(fèi)者從緩沖區(qū)中取出數(shù)據(jù)處理,兩種方式從調(diào)用方式上來說,第一種可是說是同步的,即生產(chǎn)者在生產(chǎn)出數(shù)據(jù)后要等待消費(fèi)者消耗掉后才能生產(chǎn)下一個(gè)數(shù)據(jù),等待時(shí)間的長短取決于消費(fèi)者處理數(shù)據(jù)的能力;第二種方式是異步的,生產(chǎn)者只管生產(chǎn)數(shù)據(jù),然后扔到一個(gè)緩沖區(qū)內(nèi),不管數(shù)據(jù)是否被立即處理了,消費(fèi)者則從緩沖區(qū)中依次取出數(shù)據(jù)進(jìn)行自己節(jié)奏的處理。從線程模型角度來說,第一種是單線程的,而第二種則是多線程的。多線程必須要考慮的一個(gè)問題是線程之間的協(xié)作,協(xié)作即協(xié)調(diào)合作,不要亂套,以生產(chǎn)者和消費(fèi)者模型而言,就是當(dāng)緩沖區(qū)里沒有數(shù)據(jù)時(shí)消費(fèi)者要等待,等待生產(chǎn)者生產(chǎn)數(shù)據(jù),當(dāng)緩沖區(qū)滿的時(shí)候生產(chǎn)者要等待,等待消費(fèi)者消耗掉一些數(shù)據(jù)空出位置好存放數(shù)據(jù)。 java中為了實(shí)現(xiàn)多線程之間的協(xié)助,需要用到幾個(gè)特性:wait(),notify(),notifyAll(),synchronized,synchronized相當(dāng)于操作系統(tǒng)里的臨界區(qū)或者鎖的概念,所謂臨界區(qū)就是說一次只能有一個(gè)線程進(jìn)去,其他想進(jìn)入的線程必須等待,加了synchronized鎖后,才能調(diào)用wait(),notify()和notifyAll()操作,wait方法被調(diào)用后,當(dāng)前線程A(舉例)進(jìn)入被加鎖對象的線程休息室,然后釋放鎖,等待被喚醒。釋放的鎖誰來獲???當(dāng)然是由先前等待的另一個(gè)線程B得到,B在獲得鎖后,進(jìn)行某種操作后通過notify或者notifyAll把A從線程休息室喚醒,然后釋放鎖,A被喚醒后,重新獲取鎖定,進(jìn)行下一語句的執(zhí)行。 再回到生產(chǎn)者和消費(fèi)者模型,如果引入了緩沖區(qū)的話就需要處理生產(chǎn)者線程和消費(fèi)者線程之間的協(xié)作,緩沖區(qū)可以有這幾種,隊(duì)列緩沖區(qū),比如隊(duì)列或者棧,隊(duì)列緩沖區(qū)的特點(diǎn)是其長度是動(dòng)態(tài)增長的,這就意味著內(nèi)存的動(dòng)態(tài)分配帶來的性能開銷,同時(shí)隊(duì)列緩沖區(qū)還會(huì)產(chǎn)生因?yàn)槎嗑€程之間的同步和互斥帶來的開銷。環(huán)形緩沖區(qū)可以解決內(nèi)存分配帶來開銷的問題,因?yàn)榄h(huán)形緩沖區(qū)長度是固定的。但是環(huán)形緩沖區(qū)還是無法解決同步互斥帶來的多線程切換的開銷,如果生產(chǎn)者和消費(fèi)者都不止一個(gè)線程,帶來的開銷更大,終極解決辦法是引入雙緩沖區(qū),何為雙緩沖區(qū)?雙緩沖區(qū)顧名思義是有兩個(gè)長度固定的緩沖區(qū)A B,生產(chǎn)者和消費(fèi)者只使用其中一個(gè),當(dāng)兩個(gè)緩沖區(qū)都操作完成后完成一次切換,開始時(shí)生產(chǎn)者開始向A里寫數(shù)據(jù),消費(fèi)者從B里讀取數(shù)據(jù),當(dāng)A寫滿同時(shí)B也讀完后,切換一下,這時(shí)消費(fèi)者從A里取數(shù)據(jù),生產(chǎn)者向B寫數(shù)據(jù),由于生產(chǎn)者和消費(fèi)者不會(huì)同時(shí)操作同一個(gè)緩沖區(qū),所以不會(huì)發(fā)生沖突。 生產(chǎn)者和消費(fèi)者模型不止是用在多線程之間,不同進(jìn)程之間也可以有。線程和進(jìn)程到底有什么區(qū)別?這是很多程序員搞不清的問題,其實(shí)很簡單,進(jìn)程有自己的地址空間和上下文,線程是在一個(gè)進(jìn)程上并發(fā)執(zhí)行的代碼段。其實(shí)在win32系統(tǒng)中進(jìn)程只是占用一定長度的地址空間,進(jìn)程中總是有一個(gè)主線程來運(yùn)行。消費(fèi)者和生產(chǎn)者模型應(yīng)用于進(jìn)程間通信的典型例子是分布式消息處理,消息的消費(fèi)者進(jìn)程需要一個(gè)緩沖區(qū)緩沖收到的消息,消息的生產(chǎn)者進(jìn)程也需要一個(gè)緩沖區(qū)緩沖將要發(fā)送的消息,這樣可以一定程度上減少因?yàn)榫W(wǎng)絡(luò)斷開引起的消息丟失。對于此模型,應(yīng)該明確一下幾點(diǎn):1, 生產(chǎn)者僅僅在倉儲(chǔ)未滿時(shí)生產(chǎn),倉滿則停止生產(chǎn)。2, 消費(fèi) 者僅僅在倉儲(chǔ)有產(chǎn)品時(shí)才能消費(fèi),倉空則等待。3, 當(dāng)消費(fèi)者發(fā)現(xiàn)倉儲(chǔ)沒有產(chǎn)品的時(shí)候會(huì)通知生產(chǎn)者生產(chǎn)。4, 生產(chǎn)者在生產(chǎn)出可消費(fèi)產(chǎn)品的時(shí)候,應(yīng)該通知等待的消費(fèi)者去消費(fèi)。以下是它的具體實(shí)現(xiàn): 1, public class ProducerConsumer 2, public static void main(String args) 3, SyncStack ss=new SyncStack();4, Producer p=new Producer(ss);5, Consumer c=new Consumer(ss);6, new Thread(p).start();7, new Thread(c).start();8, 9, 10,11, class WoTou 12, int id;13, WoTou(int id) 14, this.id=id;15, 16, public String toString() 17, return WoTou : +id;18, 19, 20,21, class SyncStack 22, int index=0;23, WoTou arrWT=new WoTou6;24, 25, public synchronized void push(WoTou wt) 26, while(index=arrWT.length) 27, try28, this.wait();29, catch(InterruptedException e) 30, e.printStackTrace();31, 32, 33, this.notify();34, arrWTindex=wt;35, index+;36, 37, 38, public synchronized WoTou pop() 39, while(index=0) 40, try41, this.wait();42, catch(InterruptedException e) 43, e.printStackTrace();44, 45, 46, this.notify();47, index-;48, return arrWTindex;49, 50, 51,52, class Producer implements Runnable 53, SyncStack ss=null;54, Producer(SyncStack ss) 55, this.ss=ss;56, 57, 58, public void run() 59, for(int i=0;i20;i+) 60, WoTou wt=new WoTou(i);61, ss.push(wt);62, System.out.println(生產(chǎn)了:+wt);63, try64, Thread.sleep(int)(Math.random()*2);65, catch(InterruptedException e) 66, e.printStackTrace();67, 68, 69, 70, 71,72, class Consumer implements Runnable 73, SyncStack ss=null;74, Consumer(SyncStack ss) 75, this.ss=ss;76, 77, 78, public void run() 79, for(int i=0;i20;i+) 80, WoTou wt=ss.pop();81, System.out.println(消費(fèi)了:+wt);82, try83, Thread.sleep(int)(Math.random()*1000);84, catch(InterruptedException e) 85, e.printStackTrace();86, 87, 88, 89, 附:1程序、進(jìn)程和線程程序,就是一段靜態(tài)的可執(zhí)行的代碼。進(jìn)程,就是程序的一次動(dòng)態(tài)的執(zhí)行過程。線程,是程序 從頭到尾的執(zhí)行路線,也稱為輕量級(jí)的進(jìn)程。一個(gè)進(jìn)程在執(zhí)行過程中,可以產(chǎn)生多個(gè)線程,形成多個(gè)執(zhí)行路線。但線程間是彼此相互獨(dú)立的。各個(gè)線程可以共享相同的內(nèi)存空間,并利用共享內(nèi)存來完成數(shù)據(jù)交換、實(shí)時(shí)通信和一些同步的工作。而進(jìn)程都占有不同的內(nèi)存空間。單線程是指一個(gè) 程序只有一條從開始到結(jié)束的順序的執(zhí)行路線。多線程是多個(gè)彼此獨(dú)立的線程,多條執(zhí)行路線。2.wait()、

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論