Java多线程之生产者消费者模式详解

目录
  • 1.生产者消费者模型
  • 2.实现生产者消费者模型
  • 3.生产者消费者模型的作用是什么?
  • 总结

问题:

1.什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?

2. 生产者消费者模型的作用是什么?

1. 生产者消费者模型

在生产者-消费者模式中,通常有两类线程,即生产者线程(若干个)和消费者线程(若干个)。生产者线程向消息队列加入数据,消费者线程则从消息队列消耗数据。生产者和消费者、消息队列之间的关系结构图如图:

(1) 消息队列可以用来平衡生产和消费的线程资源;

(2) 生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据 ;

(3) 消息队列是有容量限制的,消息队列满后,生产者不能再加入数据;消息队列空时,消费者不能再取出数据;

(4) 消息队列是线程安全的,在并发操作消息队列的过程中,不能出现数据不一致的情况;或者在多个线程并发更改共享数据后,不会造成出现脏数据的情况;

(5) JDK 中各种阻塞队列,采用的就是这种模式;

2. 实现生产者消费者模型

1、消息队列中存放的消息类:

/**
 * 消息队列中存放的消息类
 */
final public class Message {
    private int id;
    private int value;
    public Message(int id,int value){
        this.id = id;
        this.value = value;
    }
    public int getId() {
        return id;
    }
    public int getValue() {
        return value;
    }
}

2、实现阻塞队列(消息队列) :

import lombok.extern.slf4j.Slf4j;
import java.util.LinkedList;
/**
 * 实现一个阻塞队列(消息队列),实现java线程间通信
 */
@Slf4j
public class MessageQueue {
    // 消息队列的容量
    private int capacity;
    // 消息队列
    LinkedList<Message> messageQueue = new LinkedList<>();
    // 设置消息队列的容量
    public MessageQueue(int capacity){
        this.capacity = capacity;
    }
    // 从消息队列中取消息
    public Message take(){
        synchronized (messageQueue){
            // 如果消息队列为空
            while (messageQueue.isEmpty()){
                try {
                    log.debug("队列为空, 消费者线程等待");
                    messageQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Message message = messageQueue.removeFirst();
            log.debug("已消费消息 {}", message);
            // 走到这,说明消息队列不为null
            messageQueue.notifyAll();
            return message;
        }
    }
    // 往消息队列中放消息
    public void put(Message message){
        synchronized (messageQueue){
            // 如果消息队列已满
            while (messageQueue.size()==capacity){
                try {
                    log.debug("队列已满, 生产者线程等待");
                    messageQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            messageQueue.addLast(message);
            log.debug("已生产消息 {}", message);
            // 走到这,说明消息队列不满
            messageQueue.notifyAll();
        }
    }
}

3、测试:

public class Main {
    public static void main(String[] args) {
        MessageQueue queue = new MessageQueue(2);
        for(int i=0;i<3;i++){
            int id = i;
            new Thread(()->{
                queue.put(new Message(id,id));
            },"生产者").start();
        }
        new Thread(()->{
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = queue.take();
            }
        },"消费者").start();
    }
}

执行结果:

15:31:28.488 [生产者] DEBUG com.example.test.MessageQueue - 已生产消息 com.example.test.Message@54309a75
15:31:28.507 [生产者] DEBUG com.example.test.MessageQueue - 已生产消息 com.example.test.Message@50915389
15:31:28.507 [生产者] DEBUG com.example.test.MessageQueue - 队列已满, 生产者线程等待
15:31:29.486 [消费者] DEBUG com.example.test.MessageQueue - 已消费消息 com.example.test.Message@54309a75
15:31:29.486 [生产者] DEBUG com.example.test.MessageQueue - 已生产消息 com.example.test.Message@6340ac12
15:31:30.487 [消费者] DEBUG com.example.test.MessageQueue - 已消费消息 com.example.test.Message@50915389
15:31:31.487 [消费者] DEBUG com.example.test.MessageQueue - 已消费消息 com.example.test.Message@6340ac12
15:31:32.488 [消费者] DEBUG com.example.test.MessageQueue - 队列为空, 消费者线程等待

3. 生产者消费者模型的作用是什么?

(1) 通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ;

(2) 解耦,解耦意味着生产者和消费者之间的联系少,联系越少越可以独自发展而不需要收到相互的制约;

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java多线程生产者消费者模式实现过程解析

    单生产者与单消费者 示例: public class ProduceConsume { public static void main(String[] args) { String lock = new String(""); Produce produce = new Produce(lock); Consume consume = new Consume(lock); new Thread(() -> { while (true) { produce.setValue();

  • Java多线程之线程通信生产者消费者模式及等待唤醒机制代码详解

    前言 前面的例子都是多个线程在做相同的操作,比如4个线程都对共享数据做tickets–操作.大多情况下,程序中需要不同的线程做不同的事,比如一个线程对共享变量做tickets++操作,另一个线程对共享变量做tickets–操作,这就是大名鼎鼎的生产者和消费者模式. 正文 一,生产者-消费者模式也是多线程 生产者和消费者模式也是多线程的范例.所以其编程需要遵循多线程的规矩. 首先,既然是多线程,就必然要使用同步.上回说到,synchronized关键字在修饰函数的时候,使用的是"this"

  • 基于Java 生产者消费者模式(详细分析)

    生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模式的情况.还会分别使用wait()/nofity()/nofityAll()机制.lock()/unlock()机制实现这两种模式. 在开始介绍模式之前,先解释下wait().notify()和no

  • Java生产者消费者模式实例分析

    本文实例讲述了Java生产者消费者模式.分享给大家供大家参考,具体如下: java的生产者消费者模式,有三个部分组成,一个是生产者,一个是消费者,一个是缓存. 这么做有什么好处呢? 1.解耦(去依赖),如果是消费者直接调用生产者,那如果生产者的代码变动了,消费者的代码也需要随之变动 2.高效,如果消费者直接掉生产者,执行时间较长的话,会阻塞,影响其他业务的进行 3.负载均衡,如果消费者直接调生产者,那生产者和消费者就得在一起了,日后业务量非常大的话,要想减轻服务器的压力,想拆分生产和消费,就很困

  • Java多线程之生产者消费者模式详解

    目录 1.生产者消费者模型 2.实现生产者消费者模型 3.生产者消费者模型的作用是什么? 总结 问题: 1.什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型? 2. 生产者消费者模型的作用是什么? 1. 生产者消费者模型 在生产者-消费者模式中,通常有两类线程,即生产者线程(若干个)和消费者线程(若干个).生产者线程向消息队列加入数据,消费者线程则从消息队列消耗数据.生产者和消费者.消息队列之间的关系结构图如图: (1) 消息队列可以用来平衡生产和消费的线程资源: (2) 生产者仅负责产

  • Java多线程中的Balking模式详解

    目录 1.场景 2.详细说明 3.Balking模式的本质:停止并返回 源代码如下: 总结 1.场景 自动保存功能: 为防止电脑死机,而定期将数据内容保存到文件中的功能. 2.详细说明 当数据内容被修改时,内容才会被保存.即当写入的内容与上次写入的内容一致时,其实就没有必要执行写入操作.也就是说,以”数据内容是否一致”作为守护条件.若数据内容相同,则不执行写入操作,直接返回. 3.Balking模式的本质:停止并返回 如果现在不合适执行该操作,或者没有必要执行该操作,就停止处理,直接返回—-Ba

  • java wait()/notify() 实现生产者消费者模式详解

    java wait()/notify() 实现生产者消费者模式 java中的多线程会涉及到线程间通信,常见的线程通信方式,例如共享变量.管道流等,这里我们要实现生产者消费者模式,也需要涉及到线程通信,不过这里我们用到了java中的wait().notify()方法: wait():进入临界区的线程在运行到一部分后,发现进行后面的任务所需的资源还没有准备充分,所以调用wait()方法,让线程阻塞,等待资源,同时释放临界区的锁,此时线程的状态也从RUNNABLE状态变为WAITING状态: noti

  • JAVA多线程实现生产者消费者的实例详解

    JAVA多线程实现生产者消费者的实例详解 下面的代码实现了生产者消费者的问题 Product.Java package consumerProducer; public class Product { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } public Product(String id) { this.id=id; } publ

  • Python之两种模式的生产者消费者模型详解

    第一种使用queue队列实现: #生产者消费者模型 其实服务器集群就是这个模型 # 这里介绍的是非yield方法实现过程 import threading,time import queue q = queue.Queue(maxsize=10) def Producer(anme): # for i in range(10): # q.put('骨头%s'%i) count = 1 while True: q.put('骨头%s'%count) print('生产了骨头',count) cou

  • Java多线程中ReentrantLock与Condition详解

    一.ReentrantLock类 1.1什么是reentrantlock java.util.concurrent.lock中的Lock框架是锁定的一个抽象,它允许把锁定的实现作为Java类,而不是作为语言的特性来实现.这就为Lock的多种实现留下了空间,各种实现可能有不同的调度算法.性能特性或者锁定语义.ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,但是添加了类似锁投票.定时锁等候和可中断锁等候的一些特性.此外,它还提供了在激烈争用情况下更

  • Java多线程案例之阻塞队列详解

    目录 一.阻塞队列介绍 1.1阻塞队列特性 1.2阻塞队列的优点 二.生产者消费者模型 2.1阻塞队列对生产者的优化 三.标准库中的阻塞队列 3.1Java提供阻塞队列实现的标准类 3.2Blockingqueue基本使用 四.阻塞队列实现 4.1阻塞队列的代码实现 4.2阻塞队列搭配生产者与消费者的代码实现 一.阻塞队列介绍 1.1阻塞队列特性 阻塞队列特性: 一.安全性 二.产生阻塞效果 阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则.阻塞队列能是一种线程安全的数据结构, 并且具有

  • Java多线程之搞定最后一公里详解

    目录 绪论 一:线程安全问题 1.1 提出问题 1.2 不安全的原因 1.2.1 原子性 1.2.2 代码"优化" 二:如何解决线程不安全的问题 2.1 通过synchronized关键字 2.2 volatile 三:wait和notify关键字 3.1 wait方法 3.2 notify方法 3.3 wait和sleep对比(面试常考) 四:多线程案例 4.1 饿汉模式单线程 4.2 懒汉模式单线程 4.3 懒汉模式多线程低性能版 4.4懒汉模式-多线程版-二次判断-性能高 总结

  • Java多线程读写锁ReentrantReadWriteLock类详解

    目录 ReentrantReadWriteLock 读读共享 写写互斥 读写互斥 源码分析 写锁的获取与释放 读锁的获取与释放 参考文献 真实的多线程业务开发中,最常用到的逻辑就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务),这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的.所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率. 读写锁表示两个锁,一个是读操作相关的锁

  • Java设计模式之工厂方法模式详解

    目录 1.工厂方法是什么 2.如何实现 3.代码实现 4.工厂方法模式的优点 5.拓展 1.工厂方法是什么 众所周知,工厂是生产产品的,并且产品供消费者使用.消费者不必关心产品的生产过程,只需要关心用哪种产品就行. 在Java世界中,工厂方法模式和现实功能类似.工厂即一个工厂类,提供获得对象(产品)的方法(工厂方法).其他类(消费者)需要用到某个对象时,只需调用工厂方法就行,不必new这个对象. 2.如何实现 1)创建产品的抽象类或接口---抽象产品 2)创建具体产品的类---具体产品 3)创建

随机推荐