一文探究ArrayBlockQueue函数及应用场景

一文探究ArrayBlockingQueue函数及应用场景

介绍

ArrayBlockingQueue是Java中的一个阻塞队列实现类,它是一个支持在队列的两端插入和删除元素的线程安全队列。它的大小是有限的,当队列已满时,插入操作会阻塞线程,直到队列有空闲空间;当队列为空时,获取操作会阻塞线程,直到队列有可用元素。

使用方法

创建ArrayBlockingQueue

ArrayBlockingQueue<T> queue = new ArrayBlockingQueue<T>(capacity);
  • T表示队列中元素的类型。
  • capacity是队列的容量,即队列最多能存放多少个元素。

插入元素

queue.put(element);
  • element表示要插入的元素。
  • 如果队列已经满了,则会阻塞线程。

删除元素

queue.take();
  • 如果队列为空,则会阻塞线程,并等待有可用元素。
  • 返回队列中最开始的元素,并将其从队列中删除。

查看队列元素个数和容量

queue.size();      // 查看队列元素个数
queue.remainingCapacity();  // 查看队列剩余容量

应用场景

多线程协作

在多线程编程中,一个线程可能要等待另一个线程的操作完成才能进行下一步操作。此时,可以使用ArrayBlockingQueue来实现两个线程之间的协作。

例如,一个线程需要获取另一个线程计算的结果,可以使用一个容量为1的ArrayBlockingQueue来进行线程之间的通信。

ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1);

Thread t1 = new Thread(() -> {
    int result = calculate();  // 计算结果
    try {
        queue.put(result);     // 将结果放入队列中
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

Thread t2 = new Thread(() -> {
    try {
        int result = queue.take();  // 从队列中取出结果
        processResult(result);      // 处理结果
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

t1.start();
t2.start();

任务队列

在一些系统中,可能需要有一个任务队列,用来存放需要执行的任务。当有空闲的线程时,从任务队列中取出一个任务进行处理。

此时,可以使用一个容量为N的ArrayBlockingQueue来实现任务队列的功能。

public class TaskQueue {
    private final int queueSize = 10;
    private ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(queueSize);   

    public void enqueueTask(Runnable task) {
        try {
            queue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void processTasks() {
        while (true) {
            try {
                Runnable task = queue.take();
                task.run();   // 执行任务
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// 在主线程中使用
TaskQueue taskQueue = new TaskQueue();

Thread t1 = new Thread(() -> taskQueue.processTasks());

Thread t2 = new Thread(() -> taskQueue.enqueueTask(() -> {
    //  执行任务
}));

t1.start();
t2.start();

示例说明

示例一:使用ArrayBlockingQueue实现生产者消费者模式

public class ProducerConsumerDemo {
    private static class Producer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;

        public Producer(ArrayBlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    queue.put(i);
                    System.out.println("生产者插入元素:" + i);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class Consumer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;

        public Consumer(ArrayBlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    int element = queue.take();
                    System.out.println("消费者取出元素:" + element);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

在示例中我们创建了两个线程,一个是生产者线程,用于向队列中插入元素;一个是消费者线程,用于从队列中删除元素。

示例二:使用ArrayBlockingQueue实现线程池

public class ThreadPoolDemo {
    private ArrayBlockingQueue<Runnable> queue;
    private List<WorkerThread> threads;
    private volatile boolean shutdown = false;

    private class WorkerThread extends Thread {
        public void run() {
            while (!shutdown) {
                try {
                    Runnable task = queue.take();
                    task.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public ThreadPoolDemo(int poolSize, int queueSize) {
        queue = new ArrayBlockingQueue<>(queueSize);
        threads = new ArrayList<>(poolSize);

        for (int i = 0; i < poolSize; i++) {
            WorkerThread workerThread = new WorkerThread();
            workerThread.start();
            threads.add(workerThread);
        }
    }

    public void execute(Runnable task) {
        try {
            queue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void shutdown() {
        shutdown = true;
        for (WorkerThread thread : threads) {
            thread.interrupt();
        }
    }
}

// 在主线程中使用
ThreadPoolDemo threadPool = new ThreadPoolDemo(5, 10);

for (int i = 0; i < 20; i++) {
    final int index = i;
    threadPool.execute(() -> {
        System.out.println("执行任务" + index);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

threadPool.shutdown();

在示例中我们创建了一个线程池,包含5个工作线程和一个容量为10的任务队列。我们通过循环向线程池中提交20个任务,每个任务打印执行的编号,并暂停2秒。最后调用shutdown方法来关闭线程池。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文探究ArrayBlockQueue函数及应用场景 - Python技术站

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

相关文章

  • 基于JSP HttpServlet的详细介绍

    当谈到Java Web开发时,JSP和Servlet是不可或缺的两个技术。而HttpServlet是Servlet的一个特定类型,它是一种能够处理HTTP请求和响应的Java Servlet类。在本文中,我们将详细介绍基于JSP HttpServlet的攻略。 准备工作 在开始开发之前,我们需要确保我们的环境中正确安装并配置了以下工具: Java开发工具(如…

    Java 2023年6月15日
    00
  • 详解Java中ByteArray字节数组的输入输出流的用法

    详解Java中ByteArray字节数组的输入输出流的用法 什么是ByteArray字节数组? 在Java中,字节数组是指由若干个字节所组成的数组。字节一般是指8位二进制数,也就是一个范围在0-255的整数,因此Java中一个字节数组就是由一系列整数所组成的数组。 什么是Java中的输入输出流? Java中的输入输出流是用来实现数据的流动,将数据从输入端流入…

    Java 2023年5月26日
    00
  • JDK8环境中使用struts2的步骤详解

    首先需要确认使用的操作系统已经安装了JDK8。接下来进入正式操作步骤: 下载Struts2 从官网(https://struts.apache.org/download.cgi)下载Struts2的压缩包,并解压到一个目录中。 环境变量配置 在环境变量中添加Struts2的路径,将struts2的lib目录下所有的jar包添加到CLASSPATH中。 创建项…

    Java 2023年5月19日
    00
  • IDEA实现 springmvc的简单注册登录功能的示例代码

    以下是“IDEA实现 springmvc的简单注册登录功能的示例代码”的完整攻略: 创建 Maven Web 项目 首先,在 IDEA 中创建一个 Maven Web 项目,选择 Spring MVC。 配置 pom.xml 文件 在 pom.xml 文件中添加 Spring 相关的依赖,包括 spring-webmvc、spring-orm、spring-…

    Java 2023年5月16日
    00
  • Java反射简易教程

    下面是Java反射简易教程的完整攻略。 什么是反射? Java是一门静态语言,一般情况下,我们需要在编译时就定义好变量和类的类型。但是有些情况下,我们需要在运行时动态获取或者创建对象,这时候就需要使用反射技术。 Java反射是指程序可以访问、检测和修改它本身的某些属性或者方法,而这些属性或者方法都是在编译时完全未知的,只有在运行时才能确定。Java反射使得我…

    Java 2023年5月26日
    00
  • Java锁的作用是什么?

    Java锁的作用是什么? Java锁是Java中用于实现多线程同步的一种机制,它能够解决并发访问共享资源时可能出现的数据竞争和并发安全性问题,保证多个线程之间的共享数据的正确性。 Java锁的分类 Java锁主要分为以下两种: 互斥锁(exclusive lock),是一种基于排他性访问机制的锁,同一时间内只允许一个线程访问共享资源,其他线程必须等待该线程完…

    Java 2023年5月11日
    00
  • set_include_path和get_include_path使用及注意事项

    set_include_path和get_include_path是PHP语言中用于设置和获取当前PHP文件包含路径的函数。 set_include_path函数 set_include_path函数用于设置当前PHP文件的包含路径。其语法如下: set_include_path ( string $new_include_path ): string|fa…

    Java 2023年6月15日
    00
  • java实现计算器模板及源码

    感谢您对Java实现计算器模板及源码的关注。下面,我将详细讲解Java实现计算器模板及源码的完整攻略,包含以下内容: 确定需求 设计界面 实现程序逻辑 测试与调试 发布计算器程序 1. 确定需求 在开发计算器程序之前,我们需要先明确需求,即计算器需要完成哪些功能。一般来说,一个基本的计算器程序需要具备以下功能: 加法 减法 乘法 除法 取模 此外,还需要考虑…

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