深入理解生产消费者模式

生产消费者模式在生活中非常的常见:

也是我们最常遇到的一类问题:

生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。

注意的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

一种按照FIFO的方式存储数据,即最先到达的数据最先传输给Consumer参与者。在Java中,可以利用数组形式来存放,每次从数组下标最前端获取数据,而从数组下标最后端来缓存数据。也可以利用LinkedList来存放,每次缓存数据的时候,利用LinkedList.addLast(obj),每次获取数据的时候利用LinkedList.removeFirst();移除并且返回队列的第一个元素


package com.producer.consumer;
import java.util.Random;
/**
 * 产生要发送的message
 * @author acer
 */


public class Producer extends Thread{

private final ChannelImpl channel;
private final Random random ;
private static int id=0;

public Producer(String name, ChannelImpl channel, long seed)
{
super(name);
this.channel = channel;
this.random = new Random(seed);
}
 
@Override
public void run() 
{
try {
while(true)
{
Thread.sleep(random.nextInt(1000));
String message = " [Message.No " +nextId()+ " by " + Thread.currentThread().getName() +"]";
channel.put(message);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
*启动消息线程的id号
* @return id
*/
public static synchronized int nextId()
{
return id++;
}
}


package com.producer.consumer;
import java.util.Random;
/**
 * message 的消费者
 * @author acer
 *
 */
public class Consumer extends Thread 
{

private final ChannelImpl channel;
private final Random random;

public Consumer(String name, ChannelImpl channel, long seed)
{
super(name);
this.channel = channel;
this.random = new Random(seed);
}

@Override
public void run()
{
while(true)
{
try {
String message = channel.take();
System.out.println(message+"----------------");
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


package com.producer.consumer;


import java.util.LinkedList;


import com.google.common.eventbus.Subscribe;


/**
 * 缓存  接收Producer的message 
 * @author acer
 */
public class ChannelImpl implements Channel{

private LinkedList<String> channel = new LinkedList<String>();
private int count  ;

public ChannelImpl(int count)
{
this.count = 0;
}

/*
* 把生产message 从尾部存储到数组中
* (non-Javadoc)
* @see com.producer.consumer.Channel#put(java.lang.String)
*/
public synchronized void put(String message) throws InterruptedException
{
count++;
channel.addLast(message);
System.out.println(Thread.currentThread().getName() + " put " + message);
}

/*
* 把message从头部的位置取出来(non-Javadoc)
* @see com.producer.consumer.Channel#take()
*/
public synchronized String take() throws InterruptedException
{
if(channel.isEmpty())
{
return null;
}
count--;
String message2 = channel.removeFirst();
System.out.println(Thread.currentThread().getName() + " get " + message2 );
return message2;
}

}

测试类:

package com.producer.consumer;


/**
 * 测试消息的发送
 * @author acer
 */


public class ChannelTest {
public static void main(String[] args) 
{
/*
* 定义缓存空间的大小
*/
ChannelImpl channel = new ChannelImpl(10);

/**
* 初始化生产者
*/
new Producer("Producer 1",channel,1).start();
new Producer("Producer 2",channel,2).start();
new Producer("Producer 3",channel,3).start();
new Producer("Producer 4",channel,4).start();

/**
* 初始化消费者
*/
new Consumer("consumer 1",channel,1).start();
new Consumer("consumer 2",channel,1).start();
new Consumer("consumer 3",channel,1).start();
new Consumer("consumer 4",channel,1).start();
new Consumer("consumer 5",channel,2).start();
new Consumer("Consumer 6",channel,2).start();
new Consumer("Consumer 7",channel,3).start();
new Consumer("Consumer 8",channel,4).start();
}
}


以阻塞的方式实现:

生产者与消费者模式,其实就是线程之间的合作关系,同时又包含了互斥关系。所谓的合作就是生产者生成产品,提供消费者消费。所谓的互斥就是生产者和消费者对于中间的缓冲区是互斥访问的。

package com.producer.consumer2;
import java.util.concurrent.BlockingQueue;
import com.google.common.eventbus.Subscribe;
public class Consumer implements Runnable{
private String username;
private final BlockingQueue<String> queue;
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return username;
}
public Consumer(String username,BlockingQueue<String> bq)
{
this.username = username;
this.queue = bq;
}
public void run()
{
try {
while(true)
{
String name = queue.take();
System.out.println(name+"---------------------------");
System.out.println(username + "已经消费;产品ID号:" +name);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();

}
}


package com.producer.consumer2;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private String username;
private final BlockingQueue<String> queue;
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return username;
}
public Producer(String username,BlockingQueue<String> bq)
{
this.username = username; 
this.queue = bq;
}
public void run()
{
try {
while(true)
{
int productID = (int)(Math.random()*1000);
queue.put(String.valueOf(productID));
System.out.println(username+" 已生产完成; 产品ID号:"+productID);
System.out.println("-------------------------");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


package com.producer.consumer2;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;




public class MainTest {
private static BlockingQueue<String>  queue = new ArrayBlockingQueue<String>(10);


public static void main(String[] args) 
{
ExecutorService service = Executors.newCachedThreadPool();

Producer producer1 = new Producer("张三",queue);
Producer producer2 = new Producer("李四",queue);
Producer producer3 = new Producer("李四2",queue);

Consumer consumer1 = new Consumer("王五",queue);
Consumer consumer2 = new Consumer("赵六",queue);
Consumer consumer3 = new Consumer("马七",queue);
Consumer consumer4 = new Consumer("hello",queue);

service.submit(producer1);
service.submit(producer2);
service.submit(producer3);

service.submit(consumer1);
service.submit(consumer2);
service.submit(consumer3);
service.submit(consumer4);

}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章