Java wait和notifyAll实现简单的阻塞队列

让我来为你详细讲解如何使用Java的wait和notifyAll实现简单的阻塞队列。

什么是阻塞队列

阻塞队列是一种特殊的队列,与普通队列的区别在于,当队列满时,往队列中添加元素的操作会被阻塞,直到队列不满;而当队列为空时,从队列中取出元素的操作会被阻塞,直到队列不为空。

阻塞队列在多线程环境下使用更加安全,它可以帮助我们解决线程同步和协作的问题。

使用wait和notifyAll实现阻塞队列

使用Java的wait和notifyAll功能,我们可以比较方便地实现一个阻塞队列。具体实现过程如下:

  1. 定义一个阻塞队列类,该类中包含一个固定大小的数组用于存储元素。
  2. 定义一个计数器变量,用于记录队列中元素的个数。
  3. 定义两个锁对象(生产者锁和消费者锁),以及两个条件变量(队列不满和队列不空)。
  4. 实现阻塞队列的入队方法put和出队方法take。入队方法put将元素添加到队列中,若队列已满,则阻塞等待;出队方法take将队列中的元素取出,并将队列中的元素个数减一,若队列为空,则阻塞等待。

下面是基于上述实现思路的Java代码示例:

public class BlockingQueue<T> {
    private T[] queue;
    private int count;
    private int size;

    private Object putLock = new Object();
    private Object takeLock = new Object();

    private Condition notFull = putLock.newCondition();
    private Condition notEmpty = takeLock.newCondition();

    public BlockingQueue(int size) {
        queue = (T[]) new Object[size];
        this.size = size;
    }

    public void put(T element) {
        synchronized (putLock) {
            while (count >= size) {
                try {
                    notFull.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue[count++] = element;
            notEmpty.signal();
        }
    }

    public T take() {
        T element = null;
        synchronized (takeLock) {
            while (count == 0) {
                try {
                    notEmpty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            element = queue[--count];
            queue[count] = null;
            notFull.signal();
        }
        return element;
    }
}

示例一:线程池中的任务队列实现

下面是一个示例,该示例演示如何在线程池中使用阻塞队列来实现任务队列的功能。该线程池实现 consist of 10 workers 和 一个阻塞队列,队列大小为5,当队列满时,任务生产者的添加操作会被阻塞。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        BlockingQueue<Runnable> taskQueue = new BlockingQueue<>(5);
        for (int i = 0; i < 5; i++) {
            executorService.execute(new TaskProducer(taskQueue));
        }
        for (int i = 0; i < 5; i++) {
            executorService.execute(new TaskConsumer(taskQueue));
        }
    }

    static class TaskProducer implements Runnable {
        private BlockingQueue<Runnable> taskQueue;

        public TaskProducer(BlockingQueue<Runnable> taskQueue) {
            this.taskQueue = taskQueue;
        }

        @Override
        public void run() {
            while (true) {
                taskQueue.put(() -> System.out.println(Thread.currentThread().getName() + " is running."));
            }
        }
    }

    static class TaskConsumer implements Runnable {
        private BlockingQueue<Runnable> taskQueue;

        public TaskConsumer(BlockingQueue<Runnable> taskQueue) {
            this.taskQueue = taskQueue;
        }

        @Override
        public void run() {
            while (true) {
                Runnable task = taskQueue.take();
                task.run();
            }
        }
    }
}

示例二:生产者消费者问题实现

下面是一个示例,该示例演示如何使用阻塞队列来实现经典的生产者消费者问题。这个例子中,我们定义了一个存放字符的阻塞队列,由一个生产者线程不断往队列中添加字符,由多个消费者线程从队列中取出字符并打印。

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        BlockingQueue<Character> blockingQueue = new BlockingQueue<>(5);
        Thread producerThread = new Thread(() -> {
            String str = "hello world";
            int len = str.length();
            for (int i = 0; i < len; i++) {
                blockingQueue.put(str.charAt(i));
            }
        });
        producerThread.start();
        Thread[] consumerThreads = new Thread[3];
        for (int i = 0; i < 3; i++) {
            Thread consumerThread = new Thread(() -> {
                while (true) {
                    Character c = blockingQueue.take();
                    System.out.println(Thread.currentThread().getName() + ": " + c);
                }
            });
            consumerThreads[i] = consumerThread;
            consumerThread.start();
        }
        try {
            producerThread.join();
            for (int i = 0; i < 3; i++) {
                consumerThreads[i].interrupt();
                consumerThreads[i].join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

以上就是使用Java的wait和notifyAll实现简单的阻塞队列的完整攻略,希望对你有所帮助!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java wait和notifyAll实现简单的阻塞队列 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Spring MVC文件配置以及参数传递示例详解

    下面是关于“Spring MVC文件配置以及参数传递示例详解”的完整攻略,包含两个示例说明。 Spring MVC文件配置以及参数传递示例详解 Spring MVC是一个流行的Java Web框架,它可以帮助我们更加方便地构建Web应用程序。本文将介绍如何使用Spring MVC文件配置来配置控制器和视图,并演示如何使用控制器来处理参数传递。 步骤一:创建S…

    Java 2023年5月17日
    00
  • 老生常谈Java反射机制(必看篇)

    老生常谈Java反射机制(必看篇) 什么是Java反射机制? Java反射机制是Java提供的一种能够在运行时获取对象的信息以及修改对象的内容的方法。通过反射机制,程序可以获取任意一个类的内部信息,并且可以操作类、构造器、方法、成员变量等。 反射机制的应用场景 通过配置文件来读取实例化的对象 对框架类进行扩展 调试时查看对象的属性信息 反射机制的基本用法 获…

    Java 2023年5月26日
    00
  • java/jsp中 中文问题详解

    Java/JSP 中文问题详解 背景 在 Java/JSP 开发中,中文字符集编码问题经常会遇到。由于 Java 内部使用的是 UTF-16 编码,而 HTTP 协议传输数据时常使用的是 UTF-8 编码,所以在处理中文字符时,需要进行字符集编码转换。 常见问题 URL 参数传递问题 由于 HTTP 协议传输 URL 数据时使用的是 ASCII 编码,因此中…

    Java 2023年5月20日
    00
  • java 实现回调代码实例

    Java 实现回调是一种常见的编程模式,它可以帮助我们解决很多传统的异步编程问题。本文将为你详细讲解 Java 实现回调的完整攻略,并提供两个实例说明。 什么是回调 回调是指一种可选择的机制,应用程序可以将函数或方法(回调函数)作为参数传递到另一个函数或方法中,该函数或方法会在后续或并行线程中调用传入的函数或方法,让其完成某些操作。 回调实现 Java 中实…

    Java 2023年5月18日
    00
  • LZW压缩算法 C#源码

    LZW压缩算法是一种流行的无损压缩算法,用于压缩数据文件。以下是使用C#实现LZW压缩算法的完整攻略: 实现步骤 读取需要压缩的文件 byte[] input = File.ReadAllBytes(inputFilePath); 初始化字符表的大小,并创建哈希表用于记录字符和其对应的编码 int tableSize = 256; Dictionary&lt…

    Java 2023年5月19日
    00
  • Java SpringMVC实现国际化整合案例分析(i18n)

    Java SpringMVC实现国际化整合案例分析(i18n) 国际化(Internationalization)是指将应用程序设计成可以适应不同的语言和文化环境。在Java SpringMVC中,我们可以使用国际化(i18n)来实现多语言支持。本文将详细讲解Java SpringMVC实现国际化整合的案例分析,并提供两个示例说明。 国际化的实现原理 在Ja…

    Java 2023年5月17日
    00
  • springmvc字符编码过滤器CharacterEncodingFilter的使用

    当我们使用Spring MVC开发Web应用时,可能会发现在处理请求参数时存在中文乱码的问题,这时候我们需要使用字符编码过滤器(CharacterEncodingFilter)来解决这个问题。 以下是使用Spring MVC中字符编码过滤器的步骤: 步骤一:添加依赖项 首先,在项目的pom.xml文件中添加以下依赖项: <dependency> …

    Java 2023年5月20日
    00
  • Android应用开发中控制反转IoC设计模式使用教程

    下面就来详细讲解“Android应用开发中控制反转IoC设计模式使用教程”的完整攻略。 什么是控制反转(Inversion of Control)设计模式 控制反转是一种设计模式,用于解决简单的对象之间的处理与业务分离,使得程序更加容易维护。 在典型的Android应用程序中,一个 activity 或 fragment 负责生命周期的管理及更新视图,而业务…

    Java 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部