一、背景
在併發編程中生產者-消費者模式是一個典型的問題。是數據共享簡單而有效的手段之一。下面是這個模式的一個簡單示例
二、代碼簡介
多個數據生產者將數據存入緩衝區,一個或者多個數據消費者將數據從緩衝區取走
package com.two;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class EventStorage {
public int maxSize;
private List<Date> storage;
public EventStorage(){
maxSize=10;
storage=new LinkedList<Date>();
}
public synchronized void set(){
while(storage.size()>=10){
try{
wait();
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
storage.add(new Date());
System.out.println("set storage size :"+storage.size());
notifyAll();
}
public synchronized void get(){
while(storage.size()<=0){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("get "+((LinkedList<Date>)storage).poll());
notifyAll();
}
}
package com.two;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class Consumer implements Runnable{
private EventStorage storage;
public Consumer(EventStorage storage){
this.storage=storage;
}
@Override
public void run() {
while(true){
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" storage.get.. ");
storage.get();
}
}
}
package com.two;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class Producer implements Runnable {
private EventStorage storage;
public Producer(EventStorage storage){
this.storage=storage;
}
@Override
public void run() {
while(true){
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" storage.set ");
storage.set();
}
}
}
package com.two;
/**
* 生產者消費者主程序
*
* @author yebing.li
* @version $Id: Main.java, v 0.1 2014年7月25日 上午11:04:42 yebing.li Exp $
*/
public class Main {
public static void main(String[] args) {
EventStorage storage=new EventStorage();
Producer producer=new Producer(storage);
Thread thread1=new Thread(producer);
Consumer consumer=new Consumer(storage);
Thread thread2=new Thread(consumer);
thread1.start();
thread2.start();
}
}
三、另一種實現方式java.util.concurrent.locks.Condition
package com.two;
import java.util.Random;
public class FileMock {
private String[] content;
private int index;
public FileMock(int size,int length){
content=new String[size];
for(int i=0;i<size;i++){
StringBuilder buffer=new StringBuilder();
for(int j=0;j<length;j++){
int indice=new Random().nextInt(1000);
buffer.append(indice);
}
content[i]=buffer.toString();
}
index=0;
}
public boolean hasMoreLines(){
return index<content.length;
}
public String getLine(){
if(hasMoreLines()){
return content[index++];
}
return null;
}
}
package com.two;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Buffer {
private LinkedList<String> buffer;
private int maxSize;
private ReentrantLock lock;
private Condition lines;
private Condition space;
private boolean peedingLines;
public Buffer(int maxSize){
this.maxSize=maxSize;
buffer=new LinkedList<String>();
lock=new ReentrantLock();
lines=lock.newCondition();
space=lock.newCondition();
peedingLines=true;
}
public void insert(String line){
lock.lock();
try{
while(buffer.size()>=maxSize){
space.await();
}
buffer.offer(line);
lines.signalAll();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public String get(){
String line=null;
lock.lock();
try{
while(buffer.size()==0&&hasPeedingLines()){
lines.await();
}
if(hasPeedingLines()){
line=buffer.poll();
space.signalAll();
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
return line;
}
public void setPeedingLines(boolean peedingLines){
this.peedingLines=peedingLines;
}
public boolean hasPeedingLines(){
return peedingLines||buffer.size()>0;
}
}
package com.two;
public class Producerfile implements Runnable{
private FileMock mock;
private Buffer buffer;
public Producerfile(FileMock mock,Buffer buffer){
this.mock=mock;
this.buffer=buffer;
}
@Override
public void run() {
buffer.setPeedingLines(true);
while(mock.hasMoreLines()){
String line=mock.getLine();
System.out.println("Producerfile,content:"+line);
buffer.insert(line);
}
buffer.setPeedingLines(false);
}
}
package com.two;
public class ConsumerFile implements Runnable{
private Buffer buffer;
public ConsumerFile(Buffer buffer){
this.buffer=buffer;
}
@Override
public void run() {
while(buffer.hasPeedingLines()){
String line=buffer.get();
System.out.println(String.format("ConsumerFile content:%s", line));
}
}
}
package com.two;
public class FileMockMain {
public static void main(String[] args) {
FileMock mock=new FileMock(100,10);
Buffer buffer=new Buffer(20);
Producerfile producer=new Producerfile(mock,buffer);
Thread threadProducer=new Thread(producer,"Producer");
ConsumerFile consumers[]=new ConsumerFile[3];
Thread threadConsumer[]=new Thread[3];
for(int i=0;i<3;i++){
consumers[i]=new ConsumerFile(buffer);
threadConsumer[i]=new Thread(consumers[i],"consumer"+i);
}
threadProducer.start();
for(int i=0;i<3;i++){
threadConsumer[i].start();
}
}
}
代碼來源於《java7併發編程手冊》