java多线程系列之模式|第三篇: Producer-Consumer pattern
生产者-消费者模式
含义:顾名思义,生产者用来生产数据,可能有一到多个,消费者用来消费数据,也可能有多个,中间会有一个“桥梁参与者”,作为数据的存放以及线程之间的同步和协调。
范例程序行为:
- 厨师(MakerThread)做蛋糕,做好后放在桌子(Table)上
- 桌子最多放3个蛋糕,桌子上有空位才能放置蛋糕
- 客人(EaterThread)依次取桌子上的蛋糕,桌子上有蛋糕才能取
先放一个顺序图:
范例代码:
MakerThread:生产类
package pattern.porducer.consumer;
import java.util.Random;
public class MakerThread extends Thread {
private final Random random;
private final Table table;
private static int id=0;//统一流水号
public MakerThread(String name, long seed, Table table) {
super(name);
this.random = new Random(seed);
this.table = table;
}
@Override
public void run() {
try{
while(true){
Thread.sleep(random.nextInt(1000));
String cake="Cake No "+nextId()+" by "+getName();
table.put(cake);
}
}catch (java.lang.InterruptedException e){
e.printStackTrace();
}
}
private synchronized int nextId(){
return id++;
}
}
EaterThread:消费类
package pattern.porducer.consumer;
import java.util.Random;
public class EaterThread extends Thread {
private final Random random;
private final Table table;
public EaterThread(String name, long seed, Table table) {
super(name);
this.random =new Random(seed);
this.table = table;
}
@Override
public void run() {
try{
while(true){
String cake=table.take();
Thread.sleep(random.nextInt(1000));
}
}catch (java.lang.InterruptedException e){
e.printStackTrace();
}
}
}
Table:数据载体
package pattern.porducer.consumer;
public class Table {
private final String[] buffer;
private int tail;//下一个put的位置
private int head;//下一个take的位置
private int count;//蛋糕数
public Table(int count) {
this.buffer=new String[count];
this.count=0;
this.head=0;
this.tail=0;
}
/**
* 存放蛋糕
* @param cake
* @throws InterruptedException
*/
public synchronized void put(String cake)throws InterruptedException{
System.out.println(Thread.currentThread().getName()+" put " +cake);
while(count>=buffer.length){
wait();
}
buffer[tail]=cake;
tail=(tail+1)%buffer.length;
count++;
notifyAll();
}
public synchronized String take()throws InterruptedException{
while(count<=0){
wait();
}
String cake=buffer[head];
head=(head+1)%buffer.length;
count--;
notifyAll();
System.out.println(Thread.currentThread().getName()+" take " + cake);
return cake;
}
}
Main:测试类
package pattern.porducer.consumer;
public class Main {
public static void main(String[] args){
Table table=new Table(3);
new MakerThread("MakerThread-1",1311,table).start();
new MakerThread("MakerThread-2",2311,table).start();
new MakerThread("MakerThread-3",3311,table).start();
new EaterThread("EaterThread-1",4311,table).start();
new EaterThread("EaterThread-2",5311,table).start();
}
}
测试结果:
MakerThread-1 put Cake No 0 by MakerThread-1
EaterThread-1 take Cake No 0 by MakerThread-1
MakerThread-3 put Cake No 1 by MakerThread-3
EaterThread-2 take Cake No 1 by MakerThread-3
MakerThread-3 put Cake No 2 by MakerThread-3
MakerThread-1 put Cake No 3 by MakerThread-1
MakerThread-1 put Cake No 4 by MakerThread-1
EaterThread-1 take Cake No 2 by MakerThread-3
MakerThread-2 put Cake No 5 by MakerThread-2
MakerThread-3 put Cake No 6 by MakerThread-3
EaterThread-1 take Cake No 3 by MakerThread-1
MakerThread-2 put Cake No 7 by MakerThread-2
MakerThread-1 put Cake No 8 by MakerThread-1
EaterThread-2 take Cake No 4 by MakerThread-1
MakerThread-1 put Cake No 9 by MakerThread-1
EaterThread-1 take Cake No 5 by MakerThread-2
MakerThread-3 put Cake No 10 by MakerThread-3
MakerThread-1 put Cake No 11 by MakerThread-1
SUCCESS。