線程的協調設計模式
在這一模式中,存在Producer和Consumer兩類線程,Producer線程用於生成Data(共享數據資源),而Consumer線程用於消費Data,在Producer和Consumer之間,存在對於Data生成和消費的協調,即當不存在Data時,Consumer線程須要等待Producer線程生成新的Data,而當Data過多時,Producer線程須要等待Consumer線程消費過多的Data。在Producer–Consumer模式中,引入了Channel(管道)類,負責Data在各線程之間的協調。Producer–Consumer模式的UML類圖以下所示。數組
在上圖中,Producer線程類和Consumer線程類均包含對Channel類對象的引用,而Channel類對象封裝了Data類,並分別實現了生產和消費Data的同步方法produce和consume。在produce和consume方法中,經過使用wait和notifyAll方法進一步實現Data的協調。多線程
一個關於wait、notify、notifyAll使用的簡單示例如圖所示。ide
Producer–Consumer(生產者-消費者)模式的實現示例函數
- package com.wt.pc;
- public class Producer extends Thread{
- //對Channel對象的引用
- Channel channel = null;
- //Consumer類構造函數
- public Producer(String producerName,Channel channel)
- {
- super(producerName);
- this.channel = channel;
- }
- //Producer線程每隔500ms嘗試生成新的data
- public void run()
- {
- try{
- while(true)
- {
- channel.produce(Integer.toString(Channel.dataId++));
- Thread.sleep(500);
- }
- }catch(Exception e){}
- }
- }
- package com.wt.pc;
- public class Consumer extends Thread{
- //對Channel對象的引用
- Channel channel = null;
- //Consumer類構造函數
- public Consumer(String consumerName,Channel channel)
- {
- super(consumerName);
- this.channel = channel;
- }
- //Consumer線程每隔500ms嘗試消費data
- public void run()
- {
- try{
- while(true)
- {
- channel.consume();
- Thread.sleep(500);
- }
- }catch(Exception e){}
- }
- }
- package com.wt.pc;
- public class Channel {
- //靜態變量,用於生成data名稱
- static int dataId = 0;
- //存儲data的數組
- Data dataList[];
- //當前未消費data的頭序號
- int head;
- //當前未消費data的尾序號的下一個
- int tail;
- //當前未消費data的數目
- int count;
- //Channel類構造函數
- //數組容量爲3,其餘值初始化爲0
- public Channel()
- {
- dataList = new Data[3];
- head = 0;
- tail = 0;
- count = 0;
- }
- //produce方法,用於生成data
- public synchronized void produce(String dataName)throws Exception{
- //當數組容量已滿時,即不能再生成新data時,當前線程進入wait set
- while (count>=3)
- {
- wait();
- }
- //生成新的data
- System.out.println(Thread.currentThread().getName()+" is producing "+dataName);
- dataList[tail] = new Data();
- dataList[tail].setDataName(dataName);
- tail = (tail+1)%3;
- count++;
- Thread.sleep(400);
- //喚醒wait set中的線程
- notifyAll();
- }
- //consume方法,用於消費data
- public synchronized void consume()throws Exception{
- //當數組容量爲空時,即不能再消費data時,當前線程進入wait set
- while (count<=0)
- {
- wait();
- }
- //消費data
- System.out.println(Thread.currentThread().getName()+" is consuming "+dataList[head].getDataName());
- head = (head+1)%3;
- count--;
- Thread.sleep(300);
- //喚醒wait set中的線程
- notifyAll();
- }
- }
- package com.wt.pc;
- public class Data {
- String dataName;
- public String getDataName() {
- return dataName;
- }
- public void setDataName(String dataName) {
- this.dataName = dataName;
- }
- }
- public static void main(String args[])
- {
- Channel channel = new Channel();
- new Producer("p1",channel).start();
- new Producer("p2",channel).start();
- new Producer("p3",channel).start();
- new Consumer("c1",channel).start();
- new Consumer("c2",channel).start();
- new Consumer("c3",channel).start();
- }
p2 is producing 0 c2 is consuming 0 p3 is producing 2 p1 is producing 1 c3 is consuming 2 c1 is consuming 1 p1 is producing 5 p3 is producing 4 c2 is consuming 5 p2 is producing 3 p3 is producing 7 c1 is consuming 4 c3 is consuming 3 p3 is producing 9 p1 is producing 6 c2 is consuming 7 p2 is producing 8 c3 is consuming 9 c1 is consuming 6 p2 is producing 12 p3 is producing 10 c2 is consuming 8 ...... |
在Java多線程設計中,須要充分考慮線程之間的同步和協調。針對不一樣的應用場景,能夠採用不一樣的設計模式,已有的設計模式有Single Threaded Execution、Immutable、Guarded Suspension、Balking、Producer-Consumer、Read-Write Lock、Thread-Per-Message、Worker Thread等,具體可進一步參考網上有關「Java多線程設計模式」的教程。this