Java多執行緒 執行緒間通訊(二)

2021-08-19 22:58:12 字數 3542 閱讀 8889

一、生產者/消費者模式

在併發程式設計中使用生產者和消費者模式能夠解決絕大多數併發問題。該模式通過平衡生產線程和消費執行緒的工作能力來提高程式的整體處理資料的速度。

生產者消費者模式是通過乙個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之後不用等待消費者處理,直接扔給阻塞佇列,消費者不找生產者要資料,而是直接從阻塞佇列裡取,阻塞佇列就相當於乙個緩衝區,平衡了生產者和消費者的處理能力。

這個阻塞佇列就是用來給生產者和消費者解耦的。縱觀大多數設計模式,都會找乙個第三者出來進行解耦,如工廠模式的第三者是工廠類,模板模式的第三者是模板類。在學習一些設計模式的過程中,如果先找到這個模式的第三者,能幫助我們快速熟悉乙個設計模式。

**:二、生產者/消費者模式的實現

一生產與一消費:操作值

等待/通知模式最經典的案例就是生產者/消費者模式。但在此模式的基礎上還有很多種的變化,不過基本原理都是基於wait/notify的。在只有乙個生產者和乙個消費者的情況下,生產者和消費者交替執行,生產者每次生產乙個產品,然後通知消費者消費;消費者每次消費乙個產品,然後通知生產者執行生產任務。假設產品的倉庫中只能存放一件產品,則當產品數為1時,生產者執行緒wait;產品數為0時,消費者執行緒wait。

生產者與消費者類:

public class produce 

public void pro()

}catch(interruptedexception e)

}}

public class consume 

public void con()

}catch(interruptedexception e)

}}

相應的執行緒:

public class thp extends thread

@override

public void run() }}

public class thc extends thread

@override

public void run()

}}

主函式:

public static void main(string args)
執行後結果如下,生產者和消費者交替執行:

生產產品,產品剩餘1個

消費產品,產品剩餘0個

生產產品,產品剩餘1個

消費產品,產品剩餘0個

生產產品,產品剩餘1個

消費產品,產品剩餘0個

生產產品,產品剩餘1個

消費產品,產品剩餘0個

生產產品,產品剩餘1個

消費產品,產品剩餘0個

多生產與多消費:操作值-假死

「假死」現象其實就是全部執行緒都進入waiting等待狀態,如果全部執行緒都進入等待狀態,那麼程式就不執行任何任務了。這在使用生產者消費者模式時經常遇到。

仍舊是上述情況,如果我們把生產者和消費者程序各自建立兩個,那麼當乙個生產者執行完生產任務後,呼叫notify方法喚醒執行緒,這時,極有可能它喚醒的是另乙個生產者執行緒。而被喚醒的生產者執行緒發現倉庫中有產品,所以執行wait()方法進入等待,而此時,它沒有喚醒任何執行緒,而在就緒佇列中又不存在任何可以競爭cpu資源的就緒執行緒,這個時候,所有的執行緒都變成了等待狀態,這就是「假死」現象。

解決這個問題很簡單,notify()可能連續喚醒同類執行緒,將notify()改為notifyall()喚醒所有執行緒,則可以解決「假死」問題。在乙個生產者執行緒執行完生產任務之後,呼叫notifyall()方法,將所有的wait狀態的執行緒喚醒,使它們加入到就緒佇列中去。這時,就算另乙個生產者執行緒獲得了cpu資源,執行wait,剩下的消費者執行緒依舊會繼續競爭cpu資源,從而杜絕了所有執行緒都進入waiting狀態的「假死」現象。

多生產多與消費:操作棧

生產者與消費者模式對於集合的操作與針對值的操作有一些不同,不過在原理上基本一致。對於集合操作時,生產者負責向集合中放入資料,而消費者負責將集合中的資料取出並進行相對應的處理。這裡我們來舉乙個例子,由3個生產者和3個消費者共同工作,他們之間有乙個資料緩衝區。當緩衝區中的元素個數小於5時,生產者輪番向緩衝區中加入元素,每次生產乙個;當緩衝區中還有元素時,消費者輪番從緩衝區中取出元素。每次執行完生產/消費的任務後,程式執行notifyall()方法喚醒所有執行緒。

我們假設有三個兵工廠一起生產kar98k狙擊步槍,每次生產一把放入兵器庫(緩衝區);三個士兵輪番從兵器庫中運出槍枝,每次只能拿走一把;兵器庫中的最大容量是5把:

//緩衝區

public class mylist

//生產者類

public class pro

public void add()

}catch(interruptedexception e) }}

//消費者類

public class con

public void get()

}catch(interruptedexception e) }}

//生產者執行緒

public class thp extends thread

@override

public void run() catch(interruptedexception e)

} }}//消費者執行緒

public class thc extends thread

@override

public void run() catch(interruptedexception e)

} }}//主函式

public class run

}}

為了避免乙個執行緒長時間占用cpu執行,同時為了便於觀察多生產者和多消費者共同工作,我們在生產者執行緒和消費者執行緒內呼叫相應方法後,使用sleep使當前執行緒短暫休眠。

部分執行結果如下:

倉庫中現在有4把kar98k狙擊步槍

兵工廠3執行**生產任務...

倉庫中現在有5把kar98k狙擊步槍

士兵3將**送上前線...

倉庫中現在有4把kar98k狙擊步槍

士兵1將**送上前線...

倉庫中現在有3把kar98k狙擊步槍

士兵3將**送上前線...

倉庫中現在有2把kar98k狙擊步槍

兵工廠1執行**生產任務...

倉庫中現在有3把kar98k狙擊步槍

兵工廠2執行**生產任務...

倉庫中現在有4把kar98k狙擊步槍

兵工廠2執行**生產任務...

可以看到的是,在程式的執行過程中,每當乙個工廠生產一把槍後,會呼叫notifyall(),然後執行完同步監視器內的**之後釋放lock物件鎖,由剩下的生產者、消費者執行緒共同競爭物件鎖。每當倉庫中有五把槍時,所有生產者執行緒都會被wait阻塞;當倉庫中沒有槍時,所有消費者會wait阻塞。

Java多執行緒 執行緒間通訊

一,等待 通知機制 實現執行緒間的通訊 舉個例子 我們去飯店就餐,飯店上餐的時間不確定,如果我們一直去詢問前台,是不是很煩,我麼這時就處於等待 wait 狀態,但是 飯店肯定會有人肯定會通知 notify 那個桌的菜已經做好了,前台就會通知這桌的人,菜來了。1,主要的方法wait notify 這個...

JAVA 多執行緒 執行緒間的通訊

程式設計間通訊 其實就是多個執行緒在操作同乙個資源 但是操作的動作不同 wait notify notifyall 都使用在同步中,因為要對持有的監視器 鎖 的執行緒操作 所以要使用在同步中,因為只有同步才具有鎖 將這些操作執行緒的方法定義在object類中的原因是因為這些方法在操作同步執行緒時,都...

Java多執行緒 4 執行緒間通訊

有這麼幾個方法,它們就定義在大家都非常熟悉的object類中,但是大家卻從來沒有呼叫過,並且也不知道是做什麼的,今天就由我帶著你們熟悉一下下面的這三個方法。它們都是定義在object類中的final方法,並且只能在synchronized上下文中呼叫。如果你現在還不明白,沒關係,下面我會用乙個 生產...