多线程模拟实现生产者/消费者模型 (借鉴)

简介: 在生产者/消费者模型中,生产者Producer负责生产数据,而消费者Consumer负责使用数据。多个生产者线程会在同一时间运行,生产数据,并放到内存中一个共享的区域。期间,多个消费者线程读取内存共享区,消费里面的数据。

 在生产者/消费者模型中,生产者Producer负责生产数据,而消费者Consumer负责使用数据。多个生产者线程会在同一时间运行,生产数据,并放到内存中一个共享的区域。期间,多个消费者线程读取内存共享区,消费里面的数据。

分析

在下面Java应用程序中,生产者线程向一个线程安全的堆栈缓冲区中写(PUSH)数据,消费者从该堆栈缓冲区中读(POP)数据,这样,这个程序中同时运行的两个线程共享同一个堆栈缓冲区资源。

类Producer是生产者模型,其中的run方法中定义了生产者线程所做的操作,循环调用push()方法,将生产的100个字母送入堆栈中,每次执行完push操作后,调用sleep方法睡眠一段随机时间。

类Consumer是消费者模型,循环调用pop方法,从堆栈取出一个字母,一共取100次,每次执行完push操作后,调用sleep方法睡眠一段随机时间

同步堆栈类SynchronizedStack

package com.ailk.biapp.ci.ProducerAndConsumer;

public class SynchronizedStack {
    private int index = 0;
    private int size = 100;
    //共享内存区
    private char[] data;
    
    public SynchronizedStack(int size){
        System.out.println("栈被创建");
        this.size = size;
        data = new char[size];
    }
    
     /**
     * 生产数据
     * 
     * @param c
     */
    public synchronized void push(char c){
        while (index == size){
            try{
                System.err.println("生产数据满了");
                this.wait();//等待,直到有数据出栈
            }catch(InterruptedException e){
                 Thread.currentThread().interrupt();
                 e.printStackTrace();
            }
        }
        data[index] = c;
        index++;
        this.notify();//通知其他线程把数据出栈 
    }
    
    /**
     * 消费数据
     * 
     * @return
     */
    public synchronized char pop(){
        while (index == 0){
            try{
                System.err.println("栈空了");
                this.wait();// 等待,直到有数据出栈
            }catch(InterruptedException e){
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
        index --;//指针向下移动
        char ch = data[index];
        this.notify();//通知其他线程把数据入栈
        return ch;
    }
    
    //显示堆栈内容
    public synchronized void print(){
        for(int i = 0; i < data.length; i++){
            System.out.println(data[i]);
        }
        System.out.println();
        this.notify();// 通知其它线程显示堆栈内容
    }
    
}

生产者Product

package com.ailk.biapp.ci.ProducerAndConsumer;

public class Producer implements Runnable{
    private SynchronizedStack stack;
    
    public Producer(SynchronizedStack s){
        stack = s;
    }
    
    public void run(){
        char ch;
        for(int i = 0; i< 100; i++){
            //随机产生100个字符
            ch = (char) (Math.random() * 26 + 'A');
            stack.push(ch);
            System.out.println("Produced:" + ch);
            try{
                //每一个字符线程就休眠一下
                 Thread.sleep((int) (Math.random() * 1000));
            }catch (InterruptedException e) {
        }
    }
    }
}

消费者Consumer

package com.ailk.biapp.ci.ProducerAndConsumer;

public class Consumer implements Runnable{
    private SynchronizedStack stack;
    
    public Consumer(SynchronizedStack s){
        stack = s;
    }
    
    public void run() {
        char ch;
        for(int i = 0 ; i < 100; i++){
            ch = stack.pop();
            System.out.println("Consumed:" + ch);
        }
        try{
             Thread.sleep((int) (Math.random() * 1000));
        }catch(InterruptedException e){
            
        }
        
    }

}

测试:

package com.ailk.biapp.ci.ProducerAndConsumer;

public class ProductConsumerTest {
    public static void main(String args[]){
        // 下面的消费者类对象和生产者类对象所操作的是同一个同步堆栈对象
        SynchronizedStack stack = new SynchronizedStack(5);
        Runnable source = new Producer(stack);
        Runnable sink = new Consumer(stack);

        Thread t1 = new Thread(source);
        Thread t2 = new Thread(sink);
        t1.start();
        t2.start();
    }
}

借鉴于:http://www.cnblogs.com/linjiqin/archive/2011/04/15/2016820.html

目录
相关文章
|
2月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
152 2
|
7月前
|
安全 Java 调度
Netty源码—3.Reactor线程模型二
本文主要介绍了NioEventLoop的执行总体框架、Reactor线程执行一次事件轮询、Reactor线程处理产生IO事件的Channel、Reactor线程处理任务队列之添加任务、Reactor线程处理任务队列之执行任务、NioEventLoop总结。
|
7月前
|
安全 Java
Netty源码—2.Reactor线程模型一
本文主要介绍了关于NioEventLoop的问题整理、理解Reactor线程模型主要分三部分、NioEventLoop的创建和NioEventLoop的启动。
|
9月前
|
缓存 NoSQL 中间件
Redis的线程模型
Redis采用单线程模型确保操作的原子性,每次只执行一个操作,避免并发冲突。它通过MULTI/EXEC事务机制、Lua脚本和复合指令(如MSET、GETSET等)保证多个操作要么全成功,要么全失败,确保数据一致性。Redis事务在EXEC前失败则不执行任何操作,EXEC后失败不影响其他操作。Pipeline虽高效但不具备原子性,适合非热点时段的数据调整。Redis 7引入Function功能,支持函数复用,简化复杂业务逻辑。总结来说,Redis的单线程模型简单高效,适用于高并发场景,但仍需合理选择指令执行方式以发挥其性能优势。
225 6
|
12月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
229 1
Java—多线程实现生产消费者
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
2月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
149 6
|
5月前
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
306 83
|
2月前
|
Java 调度 数据库
Python threading模块:多线程编程的实战指南
本文深入讲解Python多线程编程,涵盖threading模块的核心用法:线程创建、生命周期、同步机制(锁、信号量、条件变量)、线程通信(队列)、守护线程与线程池应用。结合实战案例,如多线程下载器,帮助开发者提升程序并发性能,适用于I/O密集型任务处理。
250 0
|
3月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
229 16

热门文章

最新文章