Java多线程设计模式-学习笔记-Produce/Consumer模式.

1.       模式的形象描述:

生产者-消费者模式.

 

2.       模式的描述:

在这个模式中,有着建立Data参与者的线程(Producer参与者)与使用Data参与者的线程(Customer参与者)在运行,而现在要从Producer参与者,Data参与者传递给Consumer参与者.

这时,Producer参与者与Consumer参与者之间,安插额Channel参与者.并委托由Channel参与者来保管想要传递的Data参与者.Channel参与者的工作可说是Data参与者的中继站,桥梁以及沟通管道.

因为可能会有多个线程使用到Channel参与者,Channel参与者中必须进行共享互斥.Channel参与者中,”Producer参与者接收Data参与者传送Data参与者给Consumer参与者的部分使用了Guarded Suspension Pattern..

3.       模式的参与者:

3.1    生产者-Producer:

产生数据的线程.

3.2    消费者-Consumer:

使用数据的线程.

3.3    数据对象-Data:

共享的数据,Producer产生,Consumer中使用.

3.4    沟通管道-Channel:

由生产者产生数据Data放到Channel,消费者从Channel获取数据进行处理.

当程序存在多个ProducerConsumer的时候,Channel要进行共享互斥.

4.       示例程序:

4.1 示例的场景描述:

    有3名厨师会一直作蛋糕放在桌上,而有3名客人会不停的吃.

4.2  Data参与者-蛋糕(String):

4.3  Producer参与者-厨师(MakerThread):

       

         package com.quf.study.thread.produceConsumer;

import java.util.Random;

/**
 * <strong>Title : MakerThread<br></strong>
 * <strong>Description : </strong>厨师类.<br> 
 * <strong>Create on : 2008-4-29<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public final class MakerThread extends Thread {
    
    
/**
     * <code>m_random</code>-.
     
*/

    
private final Random m_random;
    
    
/**
     * <code>m_table</code>-沟通管道.
     
*/

    
private final Table m_table;
    
    
/**
     * <code>m_id</code>-蛋糕的随机号.
     
*/

    
private static int s_id;
    
    
/**
     * 构造函数
     * 
@param name - 线程的名称.
     * 
@param table - 沟通管道.
     * 
@param seed - 间隔的时间.
     
*/

    
public MakerThread(String name,Table table,long seed){
        
super(name);
        
this.m_table = table;
        
this.m_random = new Random(seed);
    }

    
    
/* (non-Javadoc)
     * @see java.lang.Thread#run()
     
*/

    
public void run(){
        
        
try {
            
            
whiletrue ) {
                Thread.sleep(
this.m_random.nextInt(1000));
                String t_cake 
= " [Cake No.] " + nextId() + " by " + getName() +"";
                
this.m_table.put(t_cake);
            }

            
        }
 catch (InterruptedException e) {
            
// TODO: handle exception
        }

    }

    
    
/**
     * 生成蛋糕的顺序号.
     * 
@return 蛋糕的顺序号.
     
*/

    
private  static synchronized int nextId(){
        
return s_id++;
    }


}
//END CLASS OF MakerThread.

4.4  Consumer参与者-客人(EaterThread):

         package com.quf.study.thread.produceConsumer;

import java.util.Random;

/**
 * <strong>Title : EaterThread<br></strong>
 * <strong>Description : </strong>顾客类.<br> 
 * <strong>Create on : 2008-4-29<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public final class EaterThread extends Thread {
    
    
private final Random m_random;
    
    
private final Table m_table;
    
    
/**
     * 构造函数
     * 
@param name - 线程名称.
     * 
@param table - 沟通管道.
     * 
@param seed - .
     
*/

    
public EaterThread(String name,Table table,long seed){
        
super(name);
        
this.m_random = new Random(seed);
        
this.m_table = table;
    }

    
    
/* (non-Javadoc)
     * @see java.lang.Thread#run()
     
*/

    
public void run() {
        
try {
            
whiletrue ){
                
this.m_table.take();
                Thread.sleep(
this.m_random.nextInt(1000));
            }

        }
 catch (InterruptedException e) {
            
// TODO: handle exception
        }

        
    }

}
//END CLASS OF EaterThread.

4.5  Channel参与者-桌子(Table):

        package com.quf.study.thread.produceConsumer;

import java.io.Serializable;

import org.apache.log4j.Logger;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * <strong>Title : Table<br></strong>
 * <strong>Description : </strong>沟通管道实现类<br> 
 * <strong>Create on : 2008-4-29<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public class Table implements Serializable {

    
/**
     * <code>serialVersionUID</code>-注释
     
*/

    
private static final long serialVersionUID = -1212823669535279450L;
    
    
private static final Logger s_logger = Logger.getLogger(Table.class);
    
/**
     * <code>m_buffer</code>-蛋糕存放的数组.
     
*/

    
private final String[] m_buffer;
    
    
/**
     * <code>m_tail</code>-下一个put的地方.
     
*/

    
private int m_tail;
    
    
/**
     * <code>m_head</code>-下一个take的地方.
     
*/

    
private int m_head;
    
    
/**
     * <code>m_count</code>-buffer内的蛋糕数量.
     
*/

    
private int m_count;

    
/**
     * 构造函数
     
*/

    
public Table(int count) {
        
// TODO Auto-generated constructor stub
        this.m_buffer = new String[count];
        
this.m_head = 0;
        
this.m_count = 0;
    }

    
    
/**
     * 放蛋糕.
     * 
@param cake - 蛋糕.
     * 
@throws InterruptedException
     
*/

    
public synchronized void put(String cake) throws InterruptedException {
        
        
if ( s_logger.isDebugEnabled() ) {
            s_logger.debug(Thread.currentThread().getName().concat(
"puts").concat(cake));
        }

        
        
whilethis.m_count >= this.m_buffer.length ) {
            wait();
        }

        
        
this.m_buffer[this.m_tail] = cake;
        
        
this.m_tail = (this.m_tail+1)%this.m_buffer.length;
        
        
this.m_count++;
        
        notifyAll();
    }

    
    
/**
     * 获取蛋糕.
     * 
@return 蛋糕.
     * 
@throws InterruptedException
     
*/

    
public synchronized String take() throws InterruptedException{
        
        
whilethis.m_count <= 0 ) {
            wait();
        }

        
        String t_cake 
= this.m_buffer[this.m_head];
        
        
this.m_head = (this.m_head+1% this.m_buffer.length;
        
        
this.m_count--;
        
        notifyAll();
        
        
if ( s_logger.isDebugEnabled() ) {
            s_logger.debug(Thread.currentThread().getName().concat(
"takes:").concat(t_cake));
        }

        
        System.out.println(Thread.currentThread().getName().concat(
" takes:").concat(t_cake));
        
        
return t_cake;
    }


    
/**
     * 
@see java.lang.Object#toString()
     
*/

    
public String toString() {
        
return new ToStringBuilder(this).toString();
    }


    
/**
     * 
@see java.lang.Object#hashCode()
     
*/

    
public int hashCode() {
        
return new HashCodeBuilder(-1073141277-504257843).appendSuper(
                
super.hashCode()).append(this.m_count).append(this.m_tail)
                .append(
this.m_head).append(this.m_buffer).toHashCode();
    }

    
}
//END CLASS OF Table.

4.6   测试类-ProduceConsumerTest:

      package com.quf.study.thread.produceConsumer;

/**
 * <strong>Title : ProduceConsumerTest<br></strong>
 * <strong>Description : </strong>Produce-Consumer模式的测试类<br> 
 * <strong>Create on : 2008-4-29<br></strong>
 * <p>
 * <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
 * <p>
 * 
@author renxin renxin777@126.com<br>
 * 
@version <strong>Java Thread Design Pattern Study</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人        修改日期        修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 
*/

public class ProduceConsumerTest {

    
/**
     * 构造函数
     
*/

    
public ProduceConsumerTest() {
        
// TODO Auto-generated constructor stub
    }

    
    
/**
     * 主方法.
     * 
@param args
     
*/

    
public static void main( String[] args ){
        
        Table t_table 
= new Table(3);
        
        
new MakerThread("MakerThread-1",t_table,31415).start();
        
new MakerThread("MakerThread-2",t_table,92653).start();
        
new MakerThread("MakerThread-3",t_table,58979).start();
        
        
new EaterThread("EaterThread-1",t_table,32384).start();
        
new EaterThread("EaterThread-2",t_table,62643).start();
        
new EaterThread("EaterThread-3",t_table,38327).start();
        
    }


}
//END CLASS OF ProduceConsumerTest .

5.       相关知识:

        5.1 以什么顺序传递Data对象:

               1.  队列.

               2.  堆栈.

                3. 优先队列.

         5.2  线程互斥/合作:

                1.   线程 的合作要想"放到中间的东西".

                2.   线程互斥要想"应保护什么东西".

         

阅读更多
个人分类: J2SE技术
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭