首页 > 编程语言 >【Java 并发】【应用】经典的生产者、消费者

【Java 并发】【应用】经典的生产者、消费者

时间:2024-02-17 10:56:11浏览次数:28  
标签:product Java Thread 生产者 InterruptedException 并发 int num public

1  前言

闲来无事,复习复习并发中常用到的一些协调多线程的工具哈。

2  基于Java队列的实现

生产者跟消费者之间要协调,他俩会出现碰撞的地方就是存放东西的容器,所以我们可以直接拿一个线程安全的队列来做容器即可,比如我这里用的 ArrayBlockingQueue:

/**
 * @author: xjx
 * @description
 */
public class SyncDemo {

    /**
     * 容器大小
     */
    private int len = 10;
    /**
     * 队列
     */
    private ArrayBlockingQueue queue = new ArrayBlockingQueue(len);

    /**
     * 生产
     * add put(阻塞) offer(不阻塞)
     */
    public void product(int num) throws InterruptedException {
        queue.put(num);
        System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num));
    }

    /**
     * 消费
     * poll(不阻塞) take(阻塞) peek(只看不取)
     */
    public int consume() throws InterruptedException {
        Object num = queue.take();
        System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num));
        return ((int) num);
    }

    public static void main(String[] args) throws InterruptedException {
        SyncDemo demo = new SyncDemo();
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.consume();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread product = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.product(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        product.start();
        consumer.start();

        product.join();
        consumer.join();
    }
}

3  基于Java内置锁的实现

那么我们不用安全队列的情况下,基于最原始的 Java 内置锁方式的实现如下:

/**
 * @author: xjx
 * @description
 */
public class SyncedDemo {

    /**
     * 容器大小
     */
    private int len = 10;
    /**
     * 容器
     */
    private List<Integer> list = Lists.newArrayListWithCapacity(len);
    /**
     * 同步对象
     */
    private final Object obj = new Object();

    /**
     * 生产
     * add put(阻塞) offer(不阻塞)
     */
    public void product(int num) throws InterruptedException {
        synchronized (obj) {
            while (list.size() == len) {
                obj.wait();
            }
            // 不满了 可以放东西了
            list.add(num);
            System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num));
            // 唤醒消费者
            obj.notify();
        }
    }

    /**
     * 消费
     * poll(不阻塞) take(阻塞) peek(只看不取)
     */
    public void consume() throws InterruptedException {
        synchronized (obj) {
            while (list.size() <= 0) {
                obj.wait();
            }
            // 不空,消费一个
            Integer num = list.remove(list.size() - 1);
            System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num));
            // 唤醒生产者
            obj.notify();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncedDemo demo = new SyncedDemo();
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.consume();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread product = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.product(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        product.start();
        consumer.start();

        product.join();
        consumer.join();
    }
}

4  基于AQS延申的同步工具类的实现

基于AQS 延申出很多同步工具类,我这里用 ReentrantLock 来实现下:

public class ReentrantSyncDemo {

    /**
     * 容器大小
     */
    private int len = 10;
    /**
     * 容器
     */
    private List<Integer> list = Lists.newArrayListWithCapacity(len);
    /**
     * 同步对象
     */
    private ReentrantLock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    /**
     * 生产
     * add put(阻塞) offer(不阻塞)
     */
    public void product(int num) throws InterruptedException {
        lock.lock();
        try {
            while (list.size() == len) {
                notFull.await();
            }
            // 不满了 可以放东西了
            list.add(num);
            System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num));
            // 唤醒消费者
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 消费
     * poll(不阻塞) take(阻塞) peek(只看不取)
     */
    public void consume() throws InterruptedException {
        lock.lock();
        try {
            while (list.size() <= 0) {
                notEmpty.await();
            }
            // 不空,消费一个
            Integer num = list.remove(list.size() - 1);
            System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num));
            // 唤醒生产者
            notFull.signal();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantSyncDemo demo = new ReentrantSyncDemo();
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.consume();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread product = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    demo.product(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        product.start();
        consumer.start();

        product.join();
        consumer.join();
    }
}

5  小结

好啦,大概先想到这三种,有理解不对的地方欢迎指正哈。

标签:product,Java,Thread,生产者,InterruptedException,并发,int,num,public
From: https://www.cnblogs.com/kukuxjx/p/18017772

相关文章

  • 想设计一个高并发的消息中间件前,先熟悉一下这些知识点
    本文分享自华为云社区《面试必问|如何设计一款高并发的消息中间件?》,作者:冰河。消息中间件涉及的知识点要想设计一个具有高并发的消息中间件,那么首先就要了解下消息中间件涉及哪些具体的知识点。通常,设计一个良好的消息中间件最少需要满足如下条件:生产者、消费者模型。支持......
  • 【常见问题】Java 8 date time type `java.time.LocalDateTime` not supported by def
    问题描述将一个包含LocalDateTime对象的集合进行序列化和反序列化时,可能会遇到以下异常:Causedby:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:Java8date/timetype`java.time.LocalDate`notsupportedbydefault:addModule"com.fasterxml.jack......
  • 关于thrift python接口和java通信出现问题解决
    真的无语,搞了一个下午。使用thrift出现错误,先说一下遇到第一个错误,如下图:那时候代码是这叼样```if__name__=='__main__':handler=MessageServiceHandler()processor=MessageService.Processor(handler)transport=TSocket.TServerSocket(None,"9090"......
  • Java中正则表达式(regex)匹配多行(Pattern.MULTILINE和Pattern.DOTALL模式)
    ​ Java中,正则表达式(regex)的处理是通过Pattern类实现的。Pattern类提供了多种标志(flags)来修改正则表达式的行为。其中,Pattern.MULTILINE和Pattern.DOTALL是两个常用的模式,它们分别用于处理多行文本和让.匹配包括行终止符在内的任意字符。 参考文档:Java中正则表达式(regex)匹......
  • (学习日记)三、BootSrap-JavaScript
    6.BootStrap6.1什么是bootstrap?-别人写好的css模板-Bootstrap中文网(bootcss.com)<!DOCTYPEhtml><html><head><title>BootStrap_Demo</title><metacharset="UTF-8"><linkrel="stylesheet"href=&quo......
  • 如何使用TailwindCSS和JavaScript构建自定义的HTML5视频播放器
    HTML5自带了一个原生视频播放器。它在浏览器中配备了简单的用户界面、功能和一些基本的控件。尽管通过浏览器的默认视频播放器的功能完美运行,但用户界面并不那么美观和时尚,总体上并不令人满意。因此,大多数现代Web应用程序和平台,如Udemy、Netflix、YouTube和AmazonPrime,不会将默......
  • 如何在 JavaScript 中使用大于和小于运算符
    在你的JavaScript程序中,你经常需要比较两个值,以确定一个是否大于另一个或小于另一个。这就是大于和小于运算符派上用场的地方。在本文中,我们将通过代码示例更详细地介绍如何使用这些运算符。(本文内容参考:java567.com)如何在JavaScript中使用大于运算符>你可以使用大于运算......
  • 在JavaScript中的防抖函数 - 通过在React中构建自动完成功能来解释
    当你将一个新应用推向生产环境时,你希望确保它用户友好。网站的性能是用户体验的关键部分。每个用户都希望网站及其内容能够快速加载。每一秒都是宝贵的,可能导致用户再也不会访问你的网站。在本指南中,我们将了解JavaScript中一个非常重要的技术,即防抖函数。然后,我将向您展示如何在......
  • JavaScript中的querySelector()方法是什么,它是如何工作的?
    在JavaScript中,有时您需要访问HTML元素。querySelector方法是一个WebAPI,它选择与传入的指定CSS选择器匹配的第一个元素。但是,更详细地说,这是如何工作的呢?在本文中,我们将看一些如何使用querySelector方法以及querySelectorAll方法的示例。(本文内容参考:java567.com)querySelector......
  • Java学习日记 Day16 正月初五,学习回归正轨!
    年前把SSM和Linux学完了,过年期间简单的做了个ssm的项目,再理解理解SSM。今天继续学了radis,也是比较重要的一个技术。radis:简单来说就是把数据存到缓存里的技术,常常和关系数据库结合使用,我们可以把数据库拿出来的数据存到缓存里,这样减少了io的次数,大大提高了效率。radis的学习大......