生产者消费者模式(Producer-Consumer)

六、生产者消费者模式(Producer-Consumer)
1、核心思想
通过管道对数据的生产者和消费者进行解耦,使二者不直接交互,从而使二者的处理速率相对来说互不影响。
2、注意通道积压
a、使用阻塞队列。
b、使用带流量控制的无界阻塞队列。
3、可复用代码

4、参考网站
Semaphore信号量控制
学习地址:http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html

Deque与LinkedBlockingDeque深入分析
学习地址:http://blog.csdn.net/vernonzheng/article/details/8267541
5、关联模式:Two-Phase模式
http://blog.csdn.net/huzhiqiangCSDN/article/details/55099853

public interface Chanel<P> {
    public P take() throws InterruptedException;
    public void put(P product) throws InterruptedException;
}

public class BlockingQueueChanel<P> implements Chanel<P> {
    //便于使用不同的队列不用改外面的代码
    private final BlockingQueue<P> queue;

    public BlockingQueueChanel(BlockingQueue<P> queue) {
        this.queue = queue;
    }

    @Override
    public P take() throws InterruptedException {
        return queue.take();
    }

    @Override
    public void put(P product) throws InterruptedException {
        queue.put(product);
    }
}

/**
* 基于Semaphore的支持流量控制的通道实现
* @author huzhiqiang
* @param


*/
public class SemaphoreBaseChanel

implements Chanel

{
//便于使用不同的队列不用改外面的代码
private final BlockingQueue

queue;
private final Semaphore semaphore;

/**
 * @param queue 阻塞队列,通常是一个无界阻塞队列
 * @param flowLimit  流量限制数
 */
public SemaphoreBaseChanel(BlockingQueue<P> queue, int flowLimit) {
    this.queue = queue;
    semaphore = new Semaphore(flowLimit);
}

@Override
public P take() throws InterruptedException {
    return queue.take();
}

@Override
public void put(P product) throws InterruptedException {
    semaphore.acquire();
    try {
        queue.put(product);
    } finally{
        semaphore.release();
    }
}

}

public class AttachmentProssor {
private final Chanel chanel = new BlockingQueueChanel(new ArrayBlockingQueue(200));

//使用了优雅终止模式,消费者实例
private final AbstractTerminatableThread indexingThread = new AbstractTerminatableThread() {
    @Override
    protected void doRun() throws Exception {
        System.out.println("consumer begin");
        File file = null;
        file = chanel.take();
        try {
            indexFile(file);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            terminationToken.reservations.decrementAndGet();
        }
    }

    private void indexFile(File file) {
        Random r = new Random();
        try {
            Thread.sleep(r.nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

public void init(){
    indexingThread.start();
}

public void shutdown() {
    indexingThread.terminate();
}

//生产方法
public void saveAttachment(){
    File file = new File("");
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    try {
        chanel.put(file);
        System.out.println("producer OK");
    } catch (InterruptedException e) {
    }
    indexingThread.terminationToken.reservations.incrementAndGet();
}

}

public class Main {
public static void main(String[] args) {
AttachmentProssor attachmentProssor = new AttachmentProssor();
attachmentProssor.init();

    new Thread(){
        public void run() {
            for(int i=0; i<1000; i++){
                attachmentProssor.saveAttachment();
            }
        };
    }.start();

    new Thread(){
        public void run() {
            for(int i=0; i<1000; i++){
                attachmentProssor.saveAttachment();
            }
        };
    }.start();

    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
    }
    attachmentProssor.shutdown();
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个可能的解法,使用 Python 的 threading 和 queue 模块实现: ```python import threading import queue import random import string BUF_SIZE = 10 # 缓冲区大小 buf = queue.Queue(BUF_SIZE) # 创建缓冲区队列 lock = threading.Lock() # 创建锁对象 # 生产者线程1,写入大写字母 def producer_upper(): while True: with lock: if not buf.full(): c = random.choice(string.ascii_uppercase) buf.put(c) print(f"生产者1写入{c}") time.sleep(random.random()) # 随机睡眠一段时间 # 生产者线程2,写入小写字母 def producer_lower(): while True: with lock: if not buf.full(): c = random.choice(string.ascii_lowercase) buf.put(c) print(f"生产者2写入{c}") time.sleep(random.random()) # 随机睡眠一段时间 # 消费者线程,读取并输出缓冲区中的字符 def consumer(): while True: with lock: if not buf.empty(): c = buf.get() print(f"消费者读取{c}") time.sleep(random.random()) # 随机睡眠一段时间 # 创建并启动线程 threads = [] threads.append(threading.Thread(target=producer_upper)) threads.append(threading.Thread(target=producer_lower)) for i in range(3): threads.append(threading.Thread(target=consumer)) for t in threads: t.start() ``` 在程序中,我们使用了 Python 的随机数模块 `random` 和字符串模块 `string`,分别用于生成随机字母和获取字母表。缓冲区队列使用了 Python 的 `queue` 模块中的 `Queue` 类,其具有线程安全的特性,可以避免多线程操作时的竞态条件问题。使用锁 `lock` 可以保证在多线程操作缓冲区时的互斥性。 在生产者消费者线程的代码中,我们使用了 with 语句来获取锁,以保证操作缓冲区时的互斥性。在每个生产者线程和消费者线程中,我们都加入了一个随机的睡眠时间,以模拟生产者消费者的生产和消费速度的不确定性。最后,我们创建了 5 个线程并启动它们。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值