线程的协调设计模式
在这一模式中,存在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