生产者-消费者问题

生产者/消费者问题

Producer/Consumer problem

  • 概念
  • Java实现
  • Python实现
  • 总结

概念

生产者-消费者(Producer-Consumer)问题是一个著名的进程/线程的同步问题。
- 它描述的是:有一群生产者在生产产品,并将这些产品提供给消费者去消费
- 为了使生产者与消费者能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池
【生产者】将生产的产品放入缓冲区中;不允许生产者向一个已装满产品的缓冲区投放产品
【消费者】从缓冲区中取走产品去消费;不允许消费者到一个空缓冲区去取产品
- 所有的生产者和消费者进程或线程都是以异步的方式运行的,但它们之间必须保持同步

Java实现

  • 产品类
public class Product {

    private long randID;    // 随机ID

    public Product(long id) {
        this.randID = id;
    }

    public long getRandID() {
        return randID;
    }

    public void setRandID(long randID) {
        this.randID = randID;
    }

}
  • 消费者类
import java.util.concurrent.Semaphore;

public class Consumer implements Runnable {

    private java.util.concurrent.ConcurrentLinkedQueue<Product> q;
    private Semaphore semaphore;
    private String name;

    public Consumer(String name,
            java.util.concurrent.ConcurrentLinkedQueue<Product> q,
            Semaphore semaphore) {
        this.name = name;
        this.q = q;
        this.semaphore = semaphore;
    }

    public void consume() throws InterruptedException {

        semaphore.acquire();

        if (q.size() > 0) {
            Product product = this.q.remove();
            System.out.println("Consumer ["+this.name+
            "] notify : consumed product num is " + product.getRandID() + "\n");
        }

    }

    @Override
    public void run() {
        while (true) {
            // 1.延时2秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 2.消费一个
            try {
                this.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
  • 生产者类
import java.util.concurrent.Semaphore;

public class Producer implements Runnable {

    private java.util.concurrent.ConcurrentLinkedQueue<Product> q;
    private Semaphore semaphore;
    private int MAX_AVAILABLE;
    private String name;

    public Producer(String name, int MAX_AVAILABLE, 
            java.util.concurrent.ConcurrentLinkedQueue<Product> q,
            Semaphore semaphore) {
        this.name = name;
        this.MAX_AVAILABLE = MAX_AVAILABLE;
        this.q = q;
        this.semaphore = semaphore;
    }

    public void produce() {

        if (q.size() < MAX_AVAILABLE) {
//          long id = System.currentTimeMillis();
            long id = (long) (Math.random() * 100);
            this.q.add(new Product(id));
            System.out.println("Producer ["+this.name
                    +"] notify : produced product num is "+id);
        }

        semaphore.release();

    }

    @Override
    public void run() {
        while (true) {
            // 1.延时1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 2.生产一个
            produce();
        }
    }

}
  • 测试类
import java.util.concurrent.Semaphore;

public class Main {

    private final static int MAX_AVAILABLE = 5;

    public static void main(String[] args) throws InterruptedException {

        java.util.concurrent.ConcurrentLinkedQueue<Product> q = 
                new java.util.concurrent.ConcurrentLinkedQueue<Product>();
        Semaphore semaphore = new Semaphore(0);

        Thread produceThread = new Thread(new Producer("p1", MAX_AVAILABLE, q, semaphore));
        Thread consumeThread = new Thread(new Consumer("c1", q, semaphore));

        produceThread.start();
        consumeThread.start();

        produceThread.join();
        consumeThread.join();
    }

}

Python实现

  • 生产者和消费者
import threading
import time
import random

# 通过信号量进行同步
semaphore = threading.Semaphore(0)  # 初始信号量为0

def consumer(): # 消费者
    print("Consumer is waiting.")
    ## Acquire a semaphore
    semaphore.acquire()  # 当信号量为0时,acquire会阻塞
    ## The consumer have access to the shared resource
    print("\tConsumer notify : consumed item number %s" % (item,))

def producer(): # 生产者
    global item
    time.sleep(2)
    ## Create a random item
    item = random.randint(0, 1000)
    print("\tProducer notify : produced item number %s" % (item,))
    ## Release a semaphore, increamenting the internal counter by one
    semaphore.release()  # 信号量 0 -> 1
  • 测试
if __name__ == '__main__':
    for i in range(0, 5):
        t1 = threading.Thread(target=producer)
        t2 = threading.Thread(target=consumer)
        t1.start()
        t2.start()
        t1.join()
        t2.join()
    print("program terminated")

总结

生产者和消费者问题的实现可以多种多样,同样的,问题的描述也可以多种多样,例如火车入站,对于一条站台轨道,多辆火车如何分配。这类问题都可以总结为对临界资源(Critical Resouce)的管理问题。

其中为实现进程互斥的进入临界区,多采用软件方法,同步机制均遵循下面4条准则:
1. 空闲让进。当无进程处于临界区时,应允许一个请求进入临界区的进程进入临界区,以有效地利用临界资源。
2. 忙则等待。当已有进程进入临界区时,因而其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问。
3. 有限等待。对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入死等状态。
4. 让权等待。当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入忙等状态。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值