生产者,消费者的几个例子

多线程应用例子2—消费者,生产者,多个缓冲区 然后再对这个简单生产者消费者问题加大难度。将消费者改成2个,缓冲池改成拥有4个缓冲区的大缓冲池。     如何来思考了这个问题了?首先根据上面分析的二点,可以知道生产者和消费者由一个变成多个的影响不大,唯一要注意的是缓冲池变大了,回顾一下《秒杀多线程第八篇 经典线程同步 信号量Semaphore》中的信号量,不难得出用二个信号量就可以解决这种缓冲池有多个缓冲区的情况——用一个信号量A来记 阅读详情

在多线程中传递数据,免不了要用生产者,消费者模式,几个例子:

Java:

public class BlockingQueueInputStream extends InputStream {
private static final String TAG = "BlockingQueueIS";

private BlockingQueue<byte[]> mData = null;
private byte[] mDataCache = null;
private boolean mFinished = false;

public BlockingQueueInputStream(int capacity) {
mData = new LinkedBlockingQueue<>(capacity);
mFinished = false;
}

public BlockingQueueInputStream(BlockingQueue<byte[]> blockingQueue) {
mData = blockingQueue;
}

public void reset() {
mFinished = false;
}

public BlockingQueue<byte[]> getBlockingQueue() {
return mData;
}

public int write(byte[] buffer) {
if(mFinished) {
return -1;
}
try {
// a deep copy since the blocking queue only store reference
 byte[] temp = Arrays.copyOf(buffer, buffer.length);
mData.put(temp);
return temp.length;
} catch (InterruptedException e) {
Dbg.e(TAG, "Write Exception", e);
return -1;
}
}

public int read() {
throw new UnsupportedOperationException("Single-byte read not supported");
}

public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}

public int read(byte[] s, int offset, int length) throws IOException {
if (mDataCache != null && mDataCache.length >= length) {
System.arraycopy(mDataCache, 0, s, offset, length);
byte[] newDataCache = new byte[mDataCache.length - length];
System.arraycopy(mDataCache, length, newDataCache, 0, newDataCache.length);
mDataCache = newDataCache;
return length;
}

int total_read = 0;
if (mDataCache != null && mDataCache.length < length) {
System.arraycopy(mDataCache, 0, s, offset, mDataCache.length);
total_read += mDataCache.length;
mDataCache = null;
}

while (total_read < length) {
try {
byte[] bytes = null;
while (!mFinished || !mData.isEmpty()) {
bytes = mData.poll(100, TimeUnit.MILLISECONDS);
if (bytes != null) {
break;
}
}
if (bytes == null) {
if (total_read > 0) {
return total_read;
} else {
return -1;
}
}
// We have extra data, save it to the cache and waiting for next read.
 if (total_read + bytes.length > length) {
mDataCache = new byte[total_read + bytes.length - length];
System.arraycopy(bytes, bytes.length - mDataCache.length, mDataCache, 0, mDataCache.length);
System.arraycopy(bytes, 0, s, total_read + offset, bytes.length - mDataCache.length);
return length;
} else {
System.arraycopy(bytes, 0, s, offset + total_read, bytes.length);
total_read += bytes.length;
}
} catch (InterruptedException e) {
Dbg.e(TAG, "Read Exception", e);
return -1;
}
}
return total_read;
}

public void close() {
mFinished = true;
mData.clear();
}
}

Java

public class MyBlockingQueue {

private Queue queue = new LinkedList();

/**
 * Make a blocking Dequeue call so that we'll only return when the queue has
 * something on it, otherwise we'll wait until something is put on it.
 *
 * @returns This will return null if the thread wait() call is interrupted.
 */
 public synchronized Object dequeue() {
Object msg = null;
while (queue.isEmpty()) {
try {
wait(100);
} catch (InterruptedException e) {
// Error return the client a null item
 return msg;
}
}
msg = queue.remove();
Log.i("myblocking", "queue poll " + queue.size());
return msg;
}

/**
 * Enqueue will add an object to this queue, and will notify any waiting
 * threads that there is an object available.
 */
 public synchronized void enqueue(Object o) {
queue.add(o);
Log.i("myblocking", "queue put " + queue.size());
// Wake up anyone waiting for something to be put on the queue.
 notifyAll();
}

public boolean isEmpty() {
return queue.isEmpty();
}
}

使用OKIO的

public class FifoInputStream extends InputStream {
private static final String TAG = FifoInputStream.class.getSimpleName();
int mSampleRate;
int mDelay;
private Pipe mPipe;
private volatile boolean mStopped = false;

public FifoInputStream(int sampleRate, int delay) {
mSampleRate = sampleRate;
mDelay = delay;
mStopped = false;
mPipe = new Pipe(mSampleRate * 2 * 10); //10s Buffer
 mPipe.sink().timeout().timeout(10000, TimeUnit.MILLISECONDS);
mPipe.source().timeout().timeout(10000, TimeUnit.MILLISECONDS);
}

@Override
 public int read() throws IOException {
return 0;
}

public void write(byte[] buffer) throws IOException {
if (mStopped) {
Log.i(TAG, "write stopped");
return;
}
int length = buffer.length;
int available = length;
if (mDelay > 0) {
mDelay = mDelay - buffer.length * 1000 / (2 * mSampleRate);
} else {
while (available > 0 && !mStopped) {
Buffer temp = new Buffer();
temp.write(buffer, length - available, available);
Log.i(TAG, "write " + available);
mPipe.sink().write(temp, available);
}
}
}

@Override
 public int read(byte[] buffer, int offset, int length) throws IOException {
if(mStopped) {
Log.i(TAG, "read stopped -1");
return -1;
}
Buffer temp = new Buffer();
// return -1 when exhausted after sink closed; if length < available, return available immediately
 long i = mPipe.source().read(temp, length);
if (i != -1) {
temp.read(buffer, offset, (int) i);
} else {
mPipe.source().close();
}
Log.i(TAG, "Fifo read " + i);
return (int) i;
}

public void close() throws IOException {
Log.i(TAG, "Fifo close");
mStopped = true;
mPipe.sink().close();
mPipe.source().close();
}
}




C++

    class RingBuffer {
    private:
        int8_t * pBase;
        int32_t mLength;
        //pRead point to the first address of real data
        int8_t * pRead = NULL;
        //pWrite point to the address after the last real data
        int8_t * pWrite = NULL;
        pthread_mutex_t ringbuffer_mutex = PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t ringbuffer_written_cond = PTHREAD_COND_INITIALIZER;
        int32_t getFreeCount();
        int32_t getDataCount();
    public:
        RingBuffer(int length);
        ~RingBuffer();
        int32_t read(void * buffer, int32_t size);
        int32_t write(void * buffer, int32_t size);
    };
int32_t mobvoi::RingBuffer::getDataCount() {
    int32_t count = pWrite - pRead;
    if (count < 0) {
        count += mLength;
    }
    return count;
}

int32_t mobvoi::RingBuffer::getFreeCount() {
    int count = 0;
    if (pRead > pWrite) {
        count = pRead - pWrite - 1;
    } else {
        count = mLength - (pWrite - pRead + 1);
    }
    return (count > 0) ? count : 0;
}
// read from ring buffer to liner buffer, blocking
int32_t mobvoi::RingBuffer::read(void * buffer, int32_t count) {
    pthread_mutex_lock(&ringbuffer_mutex);
    if (count >= mLength) {
        pthread_mutex_unlock(&ringbuffer_mutex);
        return -1;
    }
    while (count > getDataCount()) {
        pthread_cond_wait(&ringbuffer_written_cond, &ringbuffer_mutex);
    }
    if (pRead <= pWrite) {
        memcpy(buffer, pRead, count);
        pRead += count;
    } else {
        int8_t * end = pBase + mLength;
        int32_t r2e = end - pRead;
        if (count <= r2e) {
            memcpy(buffer, pRead, count);
            pRead += count;
            if (pRead == end) {
                pRead = pBase;
            }
        } else {
            memcpy(buffer, pRead, r2e);
            memcpy(buffer + r2e, pBase, count - r2e);
            pRead = pBase + count - r2e;
        }
    }
    pthread_mutex_unlock(&ringbuffer_mutex);
    return count;
}
// write data from liner buffer to ring buffer, non blocking
int32_t mobvoi::RingBuffer::write(void * buffer, int32_t count) {
    pthread_mutex_lock(&ringbuffer_mutex);
    int32_t space = getFreeCount();
    int32_t writeCount;
    if (space == 0) {
        pthread_mutex_unlock(&ringbuffer_mutex);
        return 0;
    } else {
        writeCount = count <= space ? count : space;
    }
    int8_t * end = pBase + mLength;
    if (pRead <= pWrite) {
        int32_t w2e = end - pWrite;
        if (writeCount <= w2e) {
            memcpy(pWrite, buffer, writeCount);
            pWrite += writeCount;
            if (pWrite == end) {
                pWrite = pBase;
            }
        } else {
            memcpy(pWrite, buffer, w2e);
            memcpy(pBase, buffer + w2e, writeCount - w2e);
            pWrite = pBase + writeCount - w2e;
        }
    } else {
        memcpy(pWrite, buffer, writeCount);
        pWrite += writeCount;
    }
    pthread_cond_signal(&ringbuffer_written_cond);
    pthread_mutex_unlock(&ringbuffer_mutex);
    return writeCount;
}
mobvoi::RingBuffer::RingBuffer(int length) {
    pBase = new int8_t[length + 1];
    mLength = length + 1;
    pRead = pBase;
    pWrite = pBase;
}

mobvoi::RingBuffer::~RingBuffer() {
    delete pBase;
    pBase = NULL;
    mLength = 0;
    pRead = NULL;
    pWrite = NULL;
}

Queue

class Queue {
private:
    int MAX_SIZE;
    float * A;
    int front, rear;
public:
    // Constructor - set front and rear as -1.
    // We are assuming that for an empty Queue, both front and rear will be -1.
    Queue(int size) {
        MAX_SIZE = size;
        front = -1;
        rear = -1;
        A = new float(MAX_SIZE);
    }
    ~Queue() {
        free(A);
    }
    // To check wheter Queue is empty or not
    bool IsEmpty() {
        return (front == -1 && rear == -1);
    }

    // To check whether Queue is full or not
    bool IsFull() {
        return (rear + 1) % MAX_SIZE == front ? true : false;
    }

    // Inserts an element in queue at rear end
    void Enqueue(float x) {
        if (IsFull()) {
            //return;
            Dequeue();
        }
        if (IsEmpty()) {
            front = rear = 0;
        } else {
            rear = (rear + 1) % MAX_SIZE;
        }
        A[rear] = x;
    }

    // Removes an element in Queue from front end.
    void Dequeue() {
        if (IsEmpty()) {
            return;
        } else if (front == rear) {
            rear = front = -1;
        } else {
            front = (front + 1) % MAX_SIZE;
        }
    }
    // Returns element at front of queue.
    int Front() {
        if (front == -1) {
            //cout<<"Error: cannot return front from empty queue\n";
            return -1;
        }
        return A[front];
    }

    float getMax() {
        if (IsEmpty()) {
            return -1;
        }
        float temp = A[front];
        int count = (rear + MAX_SIZE - front) % MAX_SIZE + 1;
        //std::cout<<"Queue       : ";
        for (int i = 0; i < count; i++) {
            int index = (front + i) % MAX_SIZE; // Index of element while travesing circularly from front
            //std::cout<<A[index]<<" ";
            if (temp < A[index]) {
                temp = A[index];
            }
        }
        return temp;
    }

    /*
     Printing the elements in queue from front to rear.
     This function is only to test the code.
     This is not a standard function for Queue implementation.
     */
    void Print() {
        // Finding number of elements in queue
        int count = (rear + MAX_SIZE - front) % MAX_SIZE + 1;
        //std::cout<<"Queue       : ";
        for (int i = 0; i < count; i++) {
            int index = (front + i) % MAX_SIZE; // Index of element while travesing circularly from front
            //std::cout<<A[index]<<" ";
        }
        //std::cout<<"MAX " << getMax()<<"\n\n";
    }
};



生产者/消费者模型 生产者消费者模式是通过一个容器来解决生产者和消费者之间强耦合的关系。生产者和消费者彼此之间不直接通讯,而是通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者进行消费,而是先存到阻塞队列中。消费者不直接找生产者要数据,而是从阻塞队列中拿数据。阻塞队列就相当于一个缓冲区,将生产者和消费者之间进行解耦。 如果有多个生产者或者多个消费者那么他们之间的关系如下:下面来简单实现一下生产者和消费者模型这里是使用阻塞队列来作为生产者和消费者的“交易场所”。因此需要先创建一个类。由于其可能存放的各种类型的数据或者 阅读详情

相关推荐

协程实现 - 生产者消费者

初识协程 1. 一个简单生产者消费者的例子 在多线程中一个耳熟能详经典的例子:生产者消费者。那么它在协程中的应用场景如何呢?让我们就从这个简单的例子入手,来看一看使用libco实现的生产者与消费者。 libco协程实现的生产者消费者: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #incl...

cool grass's blog 1234

InputStream数据结构分析

struct InputStream 是单个输入流的管理器。是由 add_input_stream() 函数申请内存,以及赋值 InputStream 的各个字段的。而 input_streams 数组是一个全局变量,包含了所有输入文件里面的所有输入流。

u012117034的博客 252

生产者-消费者模式

我们可以在生产者和消费者之间加一个阻塞队列(也可以是用阻塞队列实现的程序,或者是部署了阻塞队列的服务器),让生产者和消费者通过队列来进行通信,消费者把请求发送到队列里,消费者从队列中拿生产者发送的数据,生产者从队列中获取请求,把返回的响应发送到队列里。有的时候生产者生产数据的速度远远大于消费者取数据的速度,那么队列满的时候,生产者就进入阻塞状态,生产不了数据,等消费者取数据的时候才能从阻塞状态解除,继续去生产数据。在队列空的时候,出队列操作对进入阻塞,等队列不空的时候再解除阻塞,继续出队列。

BlueSakuraStar的博客 1079

生产者消费者案例

场景介绍 现有一个肯德基餐厅,厨师负责生产出汉堡,顾客想要吃掉汉堡。 有固定的五个仓位,每个仓位可以放置一个汉堡。 当仓位满了之后厨师无法继续烹饪汉堡,只能等待顾客用膳。 当仓位中都没有汉堡的情况下,顾客无汉堡可吃,只能等待厨师烹饪 以上场景便是经典的生产者消费者案例,在《计算机操作系统》这门课中会有所涉及,该场景涉及线程的同步问题。 图解 代码实现 package com.design; public class TestDemo { public static void main(Str

c546592321的博客 692

告别混乱代码!在Arduino IDE中管理多文件项目的5个必备技巧

本文分享了在Arduino IDE中管理多文件项目的5个必备技巧,帮助开发者告别混乱代码。通过代码分割和模块化设计,提升编译效率、降低内存占用,并实现功能解耦。重点介绍了头文件设计、CPP文件实现、调试技巧和工业级目录结构,让你的Arduino项目像乐高积木一样清晰易维护。

fun88的博客 361

从零开始:用ADS 2023手把手教你设计2.4GHz Wi-Fi LNA(基于ATF-54143,附模型文件)

本文详细介绍了如何使用ADS 2023软件设计2.4GHz Wi-Fi频段的低噪声放大器(LNA),基于ATF-54143晶体管。内容涵盖模型导入、直流工作点确定、稳定性优化、噪声匹配等关键步骤,并提供可下载的模型文件包,帮助工程师快速掌握LNA设计技巧。

weixin_42531128的博客 320

生产者消费者例子

使用wait和notify方法实现消费者生产者例子。 首先设计一个生产者类: package com.freshbin.day2.two; import java.util.LinkedList; import java.util.List; /** * 生产者类 * * @author freshbin * @date 2019年2月26日 下午3:31:57 */ pub...

freshbin000的博客 1739

华硕ROG玩家国度安装Ubuntu双系统避坑指南:安全启动密钥那些事儿

本文详细解析了在华硕ROG玩家国度设备上安装Ubuntu双系统时,如何正确处理BIOS中的安全启动(Secure Boot)与密钥管理,避免常见的引导失败和Windows系统无法启动问题。指南提供了从数据备份、启动盘制作到BIOS精细设置(如将OS Type改为Other OS而非简单关闭Secure Boot)以及分区规划的完整流程,确保两个系统都能稳定共存。

weixin_29219189的博客 754

写一个生产者消费者的例子

package com.shopping.test; public class ShaoKao { //串 String chuan; //肉 String rou; //烧烤的状态,初始状态为没有烧烤 boolean flag = false; public String getChuan() ...

weixin_30814329的博客 356

SAP SD模块定价过程后台配置简介

只有手工输入定价时(例如,在定价中的定价浏览屏幕中),或者只有从外部处理转移这些定价时(例如,成本核算),才将这些定价包括在确定(价格确定、输出确定,批次确定)之中。定价过程的定义和分配是SD模块中最核心的配置,包含了条件表、条件类型、存取顺序、发票类型、客户定价过程等,确定了销售订单已什么价格销售、税率、附加折扣等多个条件行程有一个定价过程。12、小计:记录该条件类型在VBAP表中是否存储,以及其后续用途,如记入信贷,占用信贷额度,记入成本等,如果需要金额暂用信贷额度的话,在小计这里选择A即可。

我小时候很黑的博客 3782

【QNX+Android虚拟化方案】00 - 系列文章链接汇总

【QNX+Android虚拟化方案】00 - 系列文章链接汇总

|~~~热爱生活、努力学习的小伙汁~~~| 1万+

linux多个生产者与消费者,Linux 并发控制的几个例子(生产者与消费者,哲学家进餐,读者写者)...

Linux 并发控制的几个例子(生产者与消费者,哲学家进餐,读者写者)今天重新开始项目,查阅资料的时候发现了几个很典型有意思的并发控制的问题,自己学习了一下,也整理了一下。1、生产者和消费者问题:a、单缓冲区问题描述:生产者向消费者提供产品,它们共享一个有界缓冲区,生产者向其中投放产品,消费者从中取得产品。同时,每个进程都互斥的占用CPU。假定生产者和消费者是互相等效的,只要缓冲区未满,生产者就可...

weixin_29839415的博客 553

YOLOv11 快速入门指南 | 10分钟吃透网络结构与新特性

2024 年 9 月 30 日,Ultralytics 发布了 YOLOv11,这是继 YOLOv8、v9、v10 之后的最新一代实时目标检测模型。 与前几代相比,YOLOv11 在保持“单阶段、实时、端到端”三大基因的同时,带来了两大核心升级:一句话总结:YOLOv11 = 更快 + 更准 + 更少参数。 2.2 微观单元:C3k2 与 C2PSA 2.2.1 C3k2 模块 作用:替换 YOLOv8 的 C2f,做跨阶段局部特征融合。 核心代码(ultralytics/nn/modules/block

shrgegrb的博客 1407

生产者消费者问题

生产者消费者问题

惜朝歌的博客 1万+

CH7034B显示模块原理图设计,已量产

显示桥接板的价值,不在于简单把 RGB 排线换成另一种接口,而在于能否把并行视频、时钟、显示控制、模拟输出和辅助配置同时组织成稳定系统。当前这张 CH7034B 原理图就是这种思路:U3 CH7034B 作为核心桥接芯片,输入侧是 LCD_R0~R7、LCD_G0~G7、LCD_B0~B7、LCD_DE、LCD_HSYNC、LCD_VSYNC、LCD_CLK 与 LCD_BL,输出侧则通过 DAC0~DAC2 和 DDC_SC/DDC_SD 形成模拟显示接口边界。

不脱发的程序猿 162

Qt Creator配置MSVC编译环境、调试环境

获取和安装:cdb.exe 在 Debugging tools for Windows 中,而现在已经不单独提供下载,只在Windows SDK 或者Windows Driver Kit里面包含 所以需要下载微软的调试工具,最少需要下载 Windows SDK。在windows上开发,一般使用Qt Creator自带mingw编译器,编译和调试都很方便,安装Qt时勾选后,自动配置完毕。但是有时候我们需要使用MSVC的编译器,这个时候我们没法直接使用,需要配置环境才能使用,以下是配置方案。

希望能帮助大家,希望大家多多支持,你们的支持是我前进的动力。 6986

生产者消费者模型

将上述场景例比到我们实际的软件开发过程中,经常会见到这样一幕:代码的某个模块负责生产数据(供货商),而生产出来的数据却不得不交给另一模块(消费者)来对其进行处理,在这之间我们必须要有一个类似上述超市的东西来存储数据(超市),这就抽象除了我们的生产者/消费者模型。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

kalvin_y_liu的博客 6940

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【Linux】生产者 消费者模型

针对上述情况,将if判断改为while循环,每一次被唤醒都要被检测,只有当队列真的是不满的情况,才会进行push。发生休眠实际上就是线程切换,当线程从休眠状态被唤醒时,因为是从临界区被切走的,所以继续从临界区内部执行。供货商可以集中生产的一大批的商品 放到超市中,让消费者随时随地来买,供货商就不生产了。如:若超市火腿肠满了,就应该让消费者先消费,若超市没有火腿肠了,就应该让生产者先生产。若队列中没有数据存在,则不该让消费者消费,若队列中数据满了,不该让生产者进行生产。

qq_62939852的博客 1036

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

生产者消费者模式

假设有两个进程(或线程)A、B和一个固定大小的缓冲区,A进程生产数据放入缓冲区,B进程从缓冲区中取出数据进行计算,这就是一个简单的生产者-消费者模型。这里的A进程相当于生产者,B进程相当于消费者。生产者/消费者模式是一种常见的并发编程模式,其中生产者线程生成数据并将其放入缓冲区,而消费者线程从缓冲区中取出数据进行处理。这种模式通过缓冲区解耦了生产者和消费者的速度差异。

fb_941219的博客 1442

java 生产者消费者 例子_java 生产者消费者例子

用synchronized wait及notify实现 简单的生产者消费者的例子。以下是代码部分/*** Test.java Create on 2014年10月10日** Copyright (c) 2014年10月10日 by dzh** @author xingyu* @version 0.0.1**/package org.dzh.thread.waitAndnotify;import ...

weixin_39573512的博客 156

【Linux —— 生产者消费者模型】

生产者消费者模型是一种并发编程模型,用于解决多线程或多进程间的数据共享和同步问题。生产者和消费者,它们通过共享的缓冲区进行通信。生产者负责生成数据并将其放入缓冲区,而消费者则从缓冲区中获取数据并进行处理。生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而共享的缓冲区进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给缓冲区,消费者不找生产者要数据,而是直接从缓冲区取,平衡了生产者和消费者的处理能力。这个缓冲区就是用来给生产者和消费者解耦的。

jokr_的博客 1279

学习和理解JAVA线程同步--生产者与消费者例子

JAVA线程同步通常需要使用sychronized对临界资源进行加锁,所谓的临界资源就是指这些线程共同使用的资源。 sychronized通常是放在方法名前,这是表示这个方法是同步的,实际上是对this加锁。 或者放在一个对象前,对某个共同使用的对象加锁。 生产者和消费者的例子是非常经典的,这里需要定义一个池子,用于往里放入产品。定义生产者不断生产产品,当池子不满的情况下可以继续放,

漫步 2399

Java的生产者消费者模型

前言 学完了线程后,我又去找了一些线程相关的练习题来练手,其中印象最深的就是生产者消费者模型这一块,为什么呢,因为它每一篇练习题里都有,开始没看懂,后面就去仔细研究了一下,哦,原来是这样,好像是懂了,那就来写写博客吧。哈哈哈…… 什么是生产者消费者模型 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲

Andy-ZhangSir的博客 1695

简单的消费者生产者模式

消费者生产者模式,就是在一个系统中,存在消费者生产者两种角色,他们通过缓冲区进行通信,生产者生产消费者所需的资料,消费者把资料制作成产品或使用 下面讲用一个简单的例子模拟生产者消费者模式 创建一个仓库类 import java.util.LinkedList; public class MyStorage { LinkedList<Object> list = new L...

weixin_43951020的博客 689
上一篇: Why singleton is bad?
下一篇: Android流媒体的实现
我把葡萄酿成酒
博客等级 码龄12年 275粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值