您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Java多線程中消費者與生產者的關系是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
多線程:CPU中各種任務在交替執行過程中,被稱為多線程處理。其中,每個任務的一次動態執行過程被稱為進程。進程執行過程中的暫停被稱為中斷。進程通過中斷被分解成若干段,每一段被稱為一個線程。
在消費者與生產者中,我們設定單個生產者的每次活動是饅頭 +1;單個消費者每次進行的是饅頭 -1;然后消費者和生產者的活動時間不確定,同時生產者和消費者的數量不確定,該經典問題我們使用多線程實現:
我們首先確定實物,即生產者的每次生成的物品,在這里我們使用饅頭代替。在WoTou的類中,我們可以看到有著自己獨特的屬性,即饅頭的 id,我們可以在控制臺清晰的看到饅頭的生產和消費過程,具體實現代碼如下:
class WoTou{ //饅頭,生產者生產的饅頭
int id;
WoTou(int id){
this.id = id;
}
public String toString(){
return "WoTou:"+ id;
}
}
我們需要確定饅頭的存儲容器,即在消費和生產發生的時候,我們需要在什么地方進行判斷,饅頭是否耗盡,或者饅頭是否滿溢。每次活動都是相當于在棧中取東西和放東西,所以我們根據棧的特性為:先進后出 原則。
class SyncStack {//籃子容器,放饅頭用的
int index = 0;
WoTou[] arrWT = new WoTou[6];
}
在籃子容器中我們簡單定義棧的最大容量為6,我們之后設定生產者的類,定義為producer類。我們知道producer有著一些自己的獨特屬性,即往籃子SyncStack中放WoTou,每次進行饅頭+1操作,還有生產者的操作Time間隔,是隔10毫秒還是5毫秒,我們使得producer類實現其Runnerable接口,調用線程的run()方法,具體代碼如下:
class Producer implements Runnable{ //生產者
SyncStack ss= null;
Producer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生產者:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
生產者在往棧中添加數據的時候,我們使用push方法進行插入。同時定義插入的饅頭數量,這里的數量并不是籃子的饅頭數量。籃子里邊雖然只能一次性裝6個饅頭,但是消費者是同時間進行操作的,所以籃子的饅頭數量在消費之后,生產者繼續進行生產,一直到生產20個饅頭為止。
消費者我們這里定義為Consumer類,消費者和生產者有一定的相似性,但是我們需要消費在籃子中拿的過程,我們使用pop操作,同時定義消費數量,以及操作間隔,這里都是使用線程的sleep(時間)方法, 代碼如下:
class Consumer implements Runnable{ //消費者
SyncStack ss= null;
Consumer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt = ss.pop();
System.out.println("消費量:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
最后我們考慮在籃子中,假如容量已滿,即生產者生產過多,消費的太慢,那么生產者需要休息;同樣的消費過快,容器數量為0,消費者開始休息。我們在兩種情況發生的時候,需要設置兩種方法,在極限情況發生的時候,進行判斷。簡單實現代碼如下:
public synchronized void push(WoTou wt){ //往籃子中放饅頭
while(index == arrWT.length){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
arrWT[index] = wt;
index++;
}鄭州人流多少錢 http://mobile.sgyy029.com/
我們需要確定是我們在生產者進行活動的時候,不能受到其他線程的影響,即我們需要保持在某一時刻只有一個線程進行操作,這種情況我們需要使用線程的一個synchronized方法。這個方法稱為死鎖,鎖定當前方法體執行的過程中,保持其獨立性。即在方法體的前面使用synchronized關鍵字修飾。
從籃子中取出饅頭的操作類似于生產者,實現代碼如下:
public synchronized WoTou pop(){ //從籃子中取饅頭
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
index--;
return arrWT[index];
}
我們會發現在上面兩種動作中,考慮到一個問題,即數量到極限之后,我們的動作停止了。生產者在籃子容量到達6時,動作停止;消費者在籃子數量到0后,停止行為。我們這時候開始使用線程的notify方法,喚醒休眠的線程,因為線程使用了wait方法,我們可以喚醒之后,在進行各自的行為。因此籃子SynStack類中詳細代碼為:
class SyncStack {//籃子容器,放饅頭用的
int index = 0;
WoTou[] arrWT = new WoTou[6];
public synchronized void push(WoTou wt){ //往籃子中放饅頭
while(index == arrWT.length){
try {
this.wait(); //線程等待
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify(); //喚醒wait的線程
arrWT[index] = wt;
index++;
}
public synchronized WoTou pop(){ //從籃子中取饅頭
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
index--;
return arrWT[index];
}
}
我們可以修改生產者和消費者的數量和操作間隔,不一定生產+1同時消費-1。我們可以根據修改進行更改代碼,上面的運行在控制臺數據
關于“Java多線程中消費者與生產者的關系是什么”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。