详解ArrayBlockQueue源码解析

yizhihongxing

详解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日

相关文章

  • Java中System.currentTimeMillis()计算方式与时间单位转换讲解

    下面是Java中System.currentTimeMillis()计算方式与时间单位转换讲解的完整攻略。 1. System.currentTimeMillis()计算方式 在Java中,我们可以通过System.currentTimeMillis()方法获取当前的毫秒数,这个毫秒数表示从1970年1月1日00:00:00 GMT起到现在的时间间隔。 这个…

    Java 2023年5月20日
    00
  • mybatis基本实例详解

    Mybatis基本实例详解 Mybatis是一款开源的持久化框架,它可以将数据库的操作和Java代码解耦,大大简化了数据访问层的开发。本文将介绍Mybatis基本实例,包含如下内容: Mybatis简介 Mybatis基本配置 Mybatis增删改查示例1 Mybatis增删改查示例2 Mybatis简介 Mybatis是一款优秀的持久层框架,它为Java开…

    Java 2023年5月20日
    00
  • spring jpa 审计功能自定义填充字段方式

    完整的“spring jpa 审计功能自定义填充字段方式”的攻略分为以下几个步骤: 借助 Spring 审计功能实现自动填充字段 自定义填充字段的值生成方式 下面我们对每个步骤进行详细说明。 一、借助 Spring 审计功能实现自动填充字段 Spring Data JPA 提供了审计功能,即自动为实体的某些特定字段填充值,比如创建时间、修改时间、创建人员、修…

    Java 2023年6月3日
    00
  • 如何为Mac安装Java和卸载Mac上的Java 7

    如何为Mac安装Java 安装Java可以让您的Mac计算机上运行Java应用程序。 步骤1:检查您是否已经安装了Java 在终端中输入以下命令,检查您的Mac上是否已经安装了Java: java -version 如果已经安装Java,您将会看到Java的版本信息。如果未安装则会提示“-bash: java: command not found”错误。 步…

    Java 2023年5月26日
    00
  • Spring Security基本架构与初始化操作流程详解

    Spring Security基本架构与初始化操作流程详解 什么是Spring Security Spring Security是一个基于Spring框架的安全解决方案,主要解决应用程序的认证和授权问题。它提供了一整套安全服务,并可在Web请求级和方法调用级处理身份验证和授权。 Spring Security基本架构 Spring Security的基本架构…

    Java 2023年5月20日
    00
  • Java 自定义错误类示例代码

    以下是Java自定义错误类的完整攻略: 自定义Java错误类 自定义Java错误类是一种创建自定义异常的方法,可以通过继承标准异常类来自定义类。自定义错误类可用于解释Java应用程序抛出的特定错误和异常。用户可以通过制定自己的错误类来自定义错误信息并创建可读性更好的异常信息。 创建一个自定义错误类 要创建一个自定义Java错误类,可以继承Exception或…

    Java 2023年5月27日
    00
  • JSP 多个文件打包下载代码

    让我们来详细讲解 “JSP 多个文件打包下载代码”的完整攻略。 1. 准备工作 在开始之前,我们需要在项目中引入如下三个依赖: <!– 需要用到的 Apache commons 库 –> <dependency> <groupId>commons-io</groupId> <artifactId&gt…

    Java 2023年6月15日
    00
  • 基于Java语言的递归运算例题详解

    针对“基于Java语言的递归运算例题详解”,我的建议如下: 一、什么是递归 在计算机科学中,递归是一种经常被用于解决问题的方法。简单来说,递归就是通过一个函数的不断调用自身来解决复杂问题的方法。 二、递归的基本原则 递归运算的基本原则有三个: 找到和确定基线条件:递归最基本的原则是将问题分解为基本的情况,然后解决这些情况。这个基本情况就是我们所说的基线条件。…

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