Producer-Consumer Pattern

本文介绍了生产者-消费者模式的基本概念及其实现方式。通过一个具体的Java程序示例,展示了如何利用同步方法解决生产者与消费者之间的数据传递问题,并讨论了队列、堆栈和优先队列的不同数据组织形式。

Producer-ConsumerPattern

Producer是“生产者”的意思,是指产生数据的线程。而Consumer是“消费者”的意思,意指使用数据的线程。

生产者必须将数据安全地交给消费者。虽然只是这样的问题,但当生产者与消费者在不同线程上运行时,两者的处理速度差将是最大的问题。当消费者要取数据时生产者还没建立出数据,或是生产者建立出数据时消费者的状态还没办法接收数据等等。

Producer-ConsumerPattern是在生产者与消费者之间加入一个“桥梁参与者”。以这个桥梁参与者与缓冲线程之间的处理速度差。

范例程序

Main 操作测试用的类

Producer模拟生产者生产数据

Consumer模拟消费者使用数据

DataNumber产生数据编号

Buffer模拟缓冲区

Buffer代码:

public class Buffer {

 

  private String[] buffer;// 模拟缓冲区

 

  private int count;// 缓冲区中数据的个数

 

  private int head;// 下一个取走数据的地方

 

  private int tail;// 下一个放置数据的地方

 

  public Buffer(int size) {

      buffer = new String[size];

 

      count = 0;

      head = 0;

      tail = 0;

  }

 

  public synchronized void put(String data)throws InterruptedException {

      while (count >= buffer.length) {

         wait();

      }

 

      buffer[tail] = data;

 

      Thread.sleep(1000);

 

      System.out.println(Thread.currentThread().getName()+ " 放入数据: " + data);

 

      tail = (tail + 1) % buffer.length;

 

      count++;

 

      notifyAll();

  }

 

  public synchronized String get() throwsInterruptedException {

      while (count <= 0) {

         wait();

      }

 

      String data = buffer[head];

 

      head = (head + 1) % buffer.length;

 

      count--;

 

      notifyAll();

 

      Thread.sleep(1000);

 

      System.out.println(Thread.currentThread().getName()+ " 取出数据: " + data);

 

      return data;

  }

 

}

DataNumber代码:

public final classDataNumber {

 

  private static int number = 1;

 

  public synchronized static int getNumber() {

      return number++;

  }

 

}

Producer代码:

public class Producerextends Thread {

 

  private Buffer buffer;

 

  public Producer(Buffer buffer, StringthreadName) {

      super(threadName);

 

      this.buffer = buffer;

  }

 

  @Override

  public void run() {

      while (true) {

         try {

             String data = "Data No."

                    +String.valueOf(DataNumber.getNumber());

             buffer.put(data);

         } catch (InterruptedException e) {

             e.printStackTrace();

         }

      }

  }

}

Consumer代码:

public class Consumerextends Thread {

 

  private Buffer buffer;

 

  public Consumer(Buffer buffer, StringthreadName) {

      super(threadName);

 

      this.buffer = buffer;

  }

 

  @Override

  public void run() {

      while (true) {

         try {

             buffer.get();

         } catch (InterruptedException e) {

             e.printStackTrace();

         }

      }

  }

}

Main代码:

public class Main {

 

  /**

   *@param args

   */

  public static void main(String[] args) {

 

      Buffer buffer = new Buffer(5);

     

      new Producer(buffer,"Producer1").start();

      new Producer(buffer,"Producer2").start();

      new Producer(buffer,"Producer3").start();

     

      new Consumer(buffer,"Consumer1").start();

      new Consumer(buffer,"Consumer2").start();

  }

 

}

从运行结果可以看出:消费者按生产者放入数据的顺序从缓冲区中取出数据。

要以什么顺序传递Data

Ø  队列——最先收到的先传

最常见的做法,是把最先收到的传出去。我们将这种方法称为FIFOFirst In First Out),先进先出或称为队列(Queue)。

Ø  堆栈——最后收到的先传

与队列相反的,最后收到的Data先传出去。这称之为LIFOLast In First Out),后进先出,又称为堆栈(stack)

Ø  优先队列——“优先”的东西先传

Data以某些条件给予优先次序,而优先性高的先传给Consumer参与者。决定优先次序的方法有很多,依应用情况而定。

队列、堆栈可以说是优先队列的特例,Data收到时间较早、优先性高的优先队列称为队列,而Data收到时间较晚、优先性高的优先队列称为堆栈。

spring: application: name: domian-location cloud: stream: bindings: locationHisFinish: destination: data.status content-type: application/json binder: data-in-binder group: location-hisfinish-consumer consumer: concurrency: 1 staSwitch: destination: data.switch content-type: application/json binder: data-in-binder group: location-switch-consumer consumer: concurrency: 1 locationRt: destination: data.calced content-type: application/json binder: data-in-binder group: location-rt-consumer consumer: concurrency: 1 locationRtHis: destination: data.calced content-type: application/json binder: data-in-binder group: location-rt-his-consumer consumer: concurrency: 1 locationHis: destination: data.calced content-type: application/json binder: data-in-binder group: location-his-consumer consumer: concurrency: 1 domianEvent: destination: domian.event content-type: application/json binder: data-in-binder webEvent: destination: data.mqtt content-type: application/json binder: data-in-binder locationMineEvent: destination: domian.event content-type: application/json binder: data-in-binder group: location-mine-consumer rabbit: bindings: locationHisFinish: consumer: exchangeType: direct maxConcurrency: 10 bindingRoutingKey: 'hisfinish' maxLength: 100000 prefetch: 16 staSwitch: consumer: exchangeType: fanout maxConcurrency: 10 bindingRoutingKey: '#' maxLength: 100000 prefetch: 16 locationRt: consumer: exchangeType: direct maxConcurrency: 10 bindingRoutingKey: RT maxLength: 100000 prefetch: 1 locationRtHis: consumer: exchangeType: direct maxConcurrency: 10 bindingRoutingKey: RT maxLength: 100000 prefetch: 1 locationHis: consumer: exchangeType: direct maxConcurrency: 10 bindingRoutingKey: HIS maxLength: 100000 domianEvent: producer: exchangeType: topic routingKeyExpression: headers.rk webEvent: producer: exchangeType: topic routingKeyExpression: headers.rk locationMineEvent: consumer: exchangeType: topic maxConcurrency: 1 bindingRoutingKey: location.mine maxLength: 10000 binders: data-in-binder: type: rabbit rabbitmq: requested-heartbeat: 10 addresses: 192.168.2.190:5672,192.168.2.179:5672,192.168.2.236:5672 username: yaxt password: yaxt-mq # data: # mongodb: # uri: mongodb://yaxt:yaxt-mongodb@192.168.2.190:17017,192.168.2.179:17017,192.168.2.236:17017/admin?replicaSet=mongos # database: Location # authentication-database: admin cache: type: simple policy: show-unknow: true still-clean: true blind-time: 300 still-speed: 0.1 station-time: false ribbon: ReadTimeout: 10000 ConnectTimeout: 5000 MaxAutoRetries: 1 MaxAutoRetriesNextServer: 1 eager-load: enabled: true clients: domian-map, jeecg-system logging: level: root: info file: name: ./log/start.log # pattern: # console: "%d - %msg%n" # file: "%d - %msg%n" logback: rollingpolicy: max-history: 180 total-size-cap: 5GB hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 50000 BaseServiceApi#queryStaffByDPC(String,String,String): execution: isolation: thread: timeoutInMilliseconds: 100000 #mybatis plus 设置 # mybatis-plus: # configuration: # # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl origin: x: 0 y: 0 z: 0 L0: 117 wgs84: display: false offset_lat: 0 offset_lng: 0 sort: orgCode: true station: landmark-switch: true 帮我看一下这个有什么问题
最新发布
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值