java多线程系列之模式|第三篇: Producer-Consumer pattern

生产者-消费者模式

含义:顾名思义,生产者用来生产数据,可能有一到多个,消费者用来消费数据,也可能有多个,中间会有一个“桥梁参与者”,作为数据的存放以及线程之间的同步和协调。

范例程序行为:

  1. 厨师(MakerThread)做蛋糕,做好后放在桌子(Table)上
  2. 桌子最多放3个蛋糕,桌子上有空位才能放置蛋糕
  3. 客人(EaterThread)依次取桌子上的蛋糕,桌子上有蛋糕才能取

先放一个顺序图:

java多线程系列之模式|第三篇: Producer-Consumer pattern

范例代码:

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。