详解ArrayBlockQueue源码解析

详解ArrayBlockingQueue源码解析

ArrayBlockingQueueJava集合框架中的阻塞队列,该队列的容量固定不变,而且是有界的。它是线程安全的,任何时刻只有一个线程能够访问队列,当队列已满时插入元素的线程会被阻塞,当队列为空时,获取元素的线程会被阻塞。

基本特性

  • 固定容量大小
  • 先进先出
  • 线程安全
  • 阻塞队列

主要方法

ArrayBlockingQueue继承了AbstractQueueAbstractCollection等接口中定义的方法,主要方法都位于ArrayBlockingQueue内部的private方法中。

插入元素

put(E e):将指定元素插入队列尾部。如果队列已满,则调用该方法的线程将会被阻塞。

移除元素

take():获取并移除队列头部元素。如果队列为空,则调用该方法的线程将会被阻塞。

查询队列中元素的个数

size():返回队列中元素的个数。

源码分析

构造方法

构造方法用于初始化队列,需要传入队列的容量以及是否公平锁,默认为非公平锁。

public ArrayBlockingQueue(int capacity) {
    this(capacity, false);
}

public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}

插入元素

put(E e)方法用于将元素插入队列尾部,当队列已满时会导致调用该方法的线程被阻塞。

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly(); // 公平锁和非公平锁都支持中断
    try {
        while (count == items.length)
            notFull.await(); // 如果队列已满,则等待
        insert(e); // 插入元素
    } finally {
        lock.unlock();
    }
}

移除元素

take()方法用于获取并移除队列头部元素,当队列为空时会导致调用该方法的线程被阻塞。

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await(); // 如果队列为空,则等待
        return extract();
    } finally {
        lock.unlock();
    }
}

查询队列中元素的个数

size()方法用于返回队列中元素的个数。

public int size() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return count;
    } finally {
        lock.unlock();
    }
}

示例说明

示例 1:

ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
new Thread(() -> {
    for (int i = 0; i < 100; i++) {
        try {
            queue.put(i);
            System.out.println("生产者生产了:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();
new Thread(() -> {
    for (int i = 0; i < 100; i++) {
        try {
            Integer num = queue.take();
            System.out.println("消费者消费了:" + num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

上述代码创建了一个容量为10的ArrayBlockingQueue,启动生产者线程向队列中生产100个整数,启动消费者线程从队列中消费100个整数。当生产者生产到10个之后,由于队列已满,会导致生产者线程被阻塞,直到队列中的元素被消费到不到10个时,生产者线程才能够继续生产。

示例 2:

ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
new Thread(() -> {
    for (int i = 0; i < 100; i++) {
        try {
            queue.put(i);
            System.out.println("生产者生产了:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();
new Thread(() -> {
    for (int i = 0; i < 100; i++) {
        try {
            Integer num = queue.take();
            System.out.println("消费者消费了:" + num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

上述代码同样创建了一个容量为10的ArrayBlockingQueue,启动生产者线程向队列中生产100个整数,启动消费者线程从队列中消费100个整数。当消费者从队列中取走所有元素后,队列为空,会导致消费者线程被阻塞,直到队列中又生产一个元素后,消费者线程才能继续消费。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解ArrayBlockQueue源码解析 - Python技术站

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

相关文章

  • SpringBoot spring.factories加载时机分析

    在SpringBoot中,spring.factories文件是一种特定的配置文件,用于向Spring容器中加载自定义的配置类或者自动配置组件。 什么是SpringBoot spring.factories文件 spring.factories文件位于META-INF目录下,它是SpringBoot用来实现自动配置的一个重要组件。该文件被用于对Spring加…

    Java 2023年5月31日
    00
  • 图片路径中含有中文在jsp下不能正常显示的原因及解决

    当图片路径中含有中文字符时,若在jsp页面中直接引用该路径,可能导致图片无法正常显示。这是因为URL是英文字符编码的,中文字符在URL中必须进行编码,如果不编码,就出现了上述问题。 为了解决这个问题,我们可以采取以下两种方法: 1. 对中文字符进行编码 使用URLEncoder对包含中文字符的字符串进行编码,然后将编码后的字符串作为图片路径。示例代码如下: …

    Java 2023年6月15日
    00
  • Jsp中request的3个基础实践

    JSP中的request对象是Web开发的一个重要组成部分,它用于在不同的Web组件之间传递数据。下面是request对象在JSP中的3个基础实践的完整攻略: 1. 在JSP页面中获取request对象 在许多情况下,我们需要在JSP页面中获取request对象。要实现这一点,我们可以使用Java中的“内置对象”- request。request作为内置对象…

    Java 2023年6月15日
    00
  • SpringMVC如何在生产环境禁用Swagger的方法

    如果您的Spring MVC项目使用了Swagger来生成文档并进行接口测试,在生产环境下禁用Swagger是一个不错的选择。本文将详细讲解如何在生产环境中禁用Swagger。 方法一:使用Profile 首先,创建一个新的profile,在该profile中配置Swagger禁用。在application.yml文件中添加以下配置,该配置将Swagger在…

    Java 2023年5月19日
    00
  • SpringBoot项目找不到javax.servlet.Filter的问题及解决

    当我们开发SpringBoot Web项目时可能会遇到一个常见的问题:找不到javax.servlet.Filter。这个问题通常出现在SpringBoot 2.x版本中,而在SpringBoot 1.x版本中则不需要特别定义依赖即可正常使用。本文将为大家分享如何解决这个问题。 问题分析: 在SpringBoot 2.x版本中需要手动添加servlet-ap…

    Java 2023年5月19日
    00
  • java加密枝术深入理解

    Java加密技术深入理解 什么是加密? 加密是指将明文(原始数据)加工处理成一段无法破解的密文的过程。通过加密,可以确保数据在传输或存储过程中的安全性,防止数据泄露或被非法篡改。 加密的分类 加密可以根据密钥是否相同,分为对称加密和非对称加密。 对称加密 对称加密是指加密和解密都使用相同的密钥。对称加密的优点是加密解密速度快,适用于对大量数据进行加密。常见的…

    Java 2023年5月19日
    00
  • Vue+java实现时间段的搜索示例

    下面是 “Vue+java实现时间段的搜索示例” 的完整攻略: 1. 准备工作 首先,我们需要准备后端接口,即搜索 API。我们可以使用 Java 和 Spring Boot 搭建一个简单的后端程序,提供时间段的搜索服务。具体实现可以参考 Spring Boot 官方文档。 接下来,我们需要准备前端框架。我们可以使用 Vue.js 来搭建一个简单的用户界面。…

    Java 2023年5月20日
    00
  • IDEA工程运行时总是报xx程序包不存在实际上包已导入(问题分析及解决方案)

    问题背景 在使用 JetBrains 旗下的 Java IDE 工具 IntelliJ IDEA 进行项目开发时,有时会遇到一个问题:在导入了某些依赖库后,运行程序时提示某些类找不到或某些程序包不存在,但实际上这些包已经被正确导入了。 问题原因 这是因为 IntelliJ IDEA 默认会在编译、运行时根据 Maven、Gradle 或自己所设置的依赖路径自…

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