深入理解生產消費者模式

生產消費者模式在生活中非常的常見:

也是我們最常遇到的一類問題:

生產者的主要作用是生成一定量的數據放到緩衝區中,然後重複此過程。與此同時,消費者也在緩衝區消耗這些數據。

注意的關鍵就是要保證生產者不會在緩衝區滿時加入數據,消費者也不會在緩衝區中空時消耗數據。

一種按照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);

}
}

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