阻塞队列-单锁实现

news2024/9/21 2:34:18

使用阻塞队列  

当我们多个线程下 对 一个队列进行操作,队列满了的情况下,其他线程再次 offer,会一直阻塞等待

对一个队列进行出队操作的时候,队列空的情况下,会一直阻塞等待删除,直到队列有元素的时候,会执行删除操作

一直阻塞等待的时候用自旋锁来进行等待

代码如下

阻塞队列接口

public interface BlockingQueue <E>{
    void offer(E e) throws InterruptedException;
    Boolean offer(E e,long timeout) throws InterruptedException;
    E poll() throws InterruptedException;
}

阻塞队列实现


public class ArrayBlockingQueue<E> implements BlockingQueue<E> {
    private final E[] array;
    private int head;//记录出队时候的头指针
    private int tail;//记录入队的指针
    private int size;//记录数组 个数
    private ReentrantLock lock = new ReentrantLock();
    private Condition headWait = lock.newCondition();//控制 入队的 同步队列
    private Condition tailWait = lock.newCondition();//控制出队的同步队列

    public ArrayBlockingQueue(int capacity) {
        array = (E[]) new Object[capacity];
    }

    private Boolean isFull() {
        return size == array.length;
    }

    private Boolean isEmpty() {
        return size == 0;
    }

    @Override
    public String toString() {
        return "ArrayBlockingQueue{" +
                "array=" + Arrays.toString(array) +
                '}';
    }

    /**
     * @param e
     * @throws InterruptedException 在判断是否满的时候 用while循环而不是 if 为了防止虚假唤醒
     */
    @Override
    public void offer(E e) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (isFull()) {
                tailWait.await();//如果满了 就让线程加入 同步队列
                // 一直等待被唤醒 使用while防止 多线程下的虚假唤醒
            }
            array[tail] = e;
            if (++tail == array.length) {
                tail = 0;
            }
            size++;
            //唤醒 出队的线程是为了 防止  在一个空队列中,删除元素的线程会一直线程等待,我们唤醒该线程
            //提示他可以删除
            headWait.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * @param e
     * @param timeout
     * @return {@code Boolean }
     * @throws InterruptedException 根据 自己传入的时间   设置 入队最多等待的时间 如果
     *                              入队超时    那么返回false 并且该线程不会再等待唤醒
     *                              跟单独使用awaitNanos方法是不一样的
     *                               单独使用 .awaitNanos 方法  当设置的等待时间到期,线程自动启动来竞争锁
     *                               ,竞争不到 会到等待队列中去等待被唤醒
     */

    @Override
    public Boolean offer(E e, long timeout) throws InterruptedException {
        lock.lockInterruptibly();
        //把传入的毫秒 转换成纳秒
        long nanos = TimeUnit.MILLISECONDS.toNanos(timeout);
        try {
            while (isFull()) {
                if (nanos < 0) {
                    //发现等待的时间 <0 表明超过了自己等待的时间 插入操作入队
                    return false;
                }
                nanos = tailWait.awaitNanos(nanos);
            }
                array[tail] = e;
                if (++tail == array.length) {
                    tail = 0;
                }
                size++;
                //唤醒 出队的线程是为了 防止  在一个空队列中,删除元素的线程会一直线程等待,我们唤醒该线程
                //提示他可以删除
                headWait.signal();
                return true;

        } finally {
            lock.unlock();
        }
    }

    @Override
    public E poll() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (isEmpty()) {
                headWait.await();
            }
            E e = array[head];
            array[head] = null;
            if (++head == array.length) {
                head = 0;
            }
            size--;
            tailWait.signal();//因为 我们 入队 满了的话线程等待
            // 删除成功之后 队列不满,唤醒入队线程
            return e;
        } finally {
            lock.unlock();
        }
    }
}

测试实现

public class ArrayBlockingQueueTest {
    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    blockingQueue.offer("任务2");
                    blockingQueue.offer("任务3");
                    blockingQueue.offer("任务4");
                    System.out.println(blockingQueue.offer("任务1", 1000));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"线程1").start();
Thread.sleep(2000);
        System.out.println(blockingQueue.toString());
    }

注意事项

我们只需要注意 condition的awaitnanos 方法,我们等待的时间一到,该线程自动唤醒争抢锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java-线程的生命周期7大状态

在 Java 中&#xff0c;线程的生命周期可以分为多个状态&#xff0c;这些状态描述了线程从创建到终止的整个过程。Java 线程的生命周期主要包括以下七大状态&#xff1a; 1.新建状态&#xff08;New&#xff09; 当一个线程对象被创建但尚未调用 start() 方法时&#xff0c;线…

Zabbix结合Grafana

一、Grafana简介 Grafana 是 Graphite 和 InfluxDB 仪表盘和图形编辑器。Grafana 是开源的&#xff0c;功能齐全的度量仪表盘和图形编辑器&#xff0c;支持 Graphite&#xff0c;InfluxDB 和 OpenTSDB。 Grafana 主要特性&#xff1a;灵活丰富的图形化选项&#xff1b;可以混合…

数分基础(06)商业分析四种类型简介

文章目录 1. 商业分析2. 四种类型2.1 描述性分析和诊断性分析2.1.1 加载Global_Superstore数据集2.1.2 描述性分析2.1.3 诊断性分析2.1.4 再进一步各地区的订单数量和平均订单金额按客户群体分析销售额和利润折扣率和利润产品类别和子类别的销售和利润 本小节小结 2.2 销售预测…

Nature:最大扩散强化学习

转自&#xff1a;清熙 强化学习&#xff08;RL&#xff09;智能体&#xff08;Agent&#xff09;常常很难在现实世界中广泛部署&#xff1a;初始化差异影响大&#xff0c;样本效率低下&#xff0c;情境之外难以泛化。 研究发现问题的关键是违反了数据独立同分布 (iid) 的假设…

驱动(RK3588S)第六课时:linux2.6的使用与GPIO子系统的使用

目录 一、Linux2.6 字符设备驱动编写框架1、合成一个完整的设备号函数2、从完整的设备号里提取主设备号3、动态申请设备号4、静态申请设备号5、释放申请的设备号6、Linux2.6 字符设备驱动的核心结构体7、初始化核心结构体8、向内核去申请 linux2.6 字符设备9、释放申请的设备10…

Linux实验报告2-初步使用shell

目录 一&#xff1a;实验目的 二&#xff1a;实验内容 1 请指出下面每条命令中哪部分是命令名、选项和参数 3 以列表及递归方式查看/dev目录下的文件。 4 修改当前系统时间为2015年1月1日。 7 查看/tmp目录下的所有文件&#xff0c;指出哪些属于隐藏文件。 8 统计文件/e…

Kaggle竞赛:Rossmann Store Sales第66名策略复现

之前做过一次Kaggle的时间序列竞赛数据集练习&#xff1a;CSDN链接效果并不理想&#xff0c;之后在Kaggle的评论中又找到了各式各样的模型方法&#xff0c;其中我还手动还原过第三名的Entity Embedding&#xff1a;CSDN链接。这个参赛方法中&#xff0c;使用了除了比赛给出的数…

MySQL之UDF提权复现

什么是UDF&#xff1a; UDF(Userfined function)用户自定义函数&#xff0c;是MySQL的一个扩展接口&#xff0c;用户通过自定义函数可以实现在 MySQL 中无法方便实现的功能&#xff0c;其添加的新函数都可以在 SQL 语句中调用。 提权条件&#xff1a; 知道MySQL用户名和密码…

探索 Nuxt Devtools:功能全面指南

title: 探索 Nuxt Devtools:功能全面指南 date: 2024/9/3 updated: 2024/9/3 author: cmdragon excerpt: 摘要:本文介绍了Nuxt Devtools的功能和使用方法,包括自动安装、手动安装和各项主要功能,如页面、组件、构建分析等。 categories: 前端开发tags: NuxtDevtools前端…

【AI】Pytorch_损失函数优化器

建议点赞收藏关注&#xff01;持续更新至pytorch大部分内容更完。 本文已达到10w字&#xff0c;故按模块拆开&#xff0c;详见目录导航。 整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 损失函数创建损失函数 &#xff08;共18个&#xff09;nn.CrossEnt…

《CounTR: Transformer-based Generalised Visual Counting》CVPR2023

摘要 本论文考虑了通用视觉对象计数问题&#xff0c;目标是开发一个计算模型&#xff0c;用于计算任意语义类别的对象数量&#xff0c;使用任意数量的“样本”&#xff08;即可能为零样本或少样本计数&#xff09;。作者提出了一个新颖的基于Transformer的架构&#xff0c;称为…

【前端面试】leetcode树javascript

写一个树 // 定义二叉树节点 function TreeNode(val, left, right) {this.val = (val === undefined ? 0 : val)this.left = (left === undefined ? null : left)this.right = (right === undefined ? null : right) }// 示例使用 const root = new TreeNode(1,new TreeNod…

Javaweb开发总结(2)

1.处理项目中的异常 利用全局异常处理器 单独创建一个类来处理全局的异常&#xff0c;并对其做出相应回应 /* * 全局异常处理器 * */ RestControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class)//代表我们要捕获所有异常public Result ex…

STL-string对字符串进行操作

C形式下的字符串:c_str() string s1("hello"); const char* str s1.c_str(); while (*str) {cout << *str << " ";str; } cout << "\n"; 获取字符数组首地址&#xff0c;用C字符串的形式遍历 区别&#xff1a; cout <…

c++实现生产者消费者的供需关系

一、生产者&消费者模式 生产者-消费者模式&#xff08;Producer-Consumer Pattern&#xff09;是一种常见的并发设计模式&#xff0c;这种模式最常见&#xff0c;所以把它单独拿出来&#xff0c;这种模式用于处理生产者和消费者之间的协调问题。生产者和消费者之间不直接关…

leveldb源码解析(一)——编解码

leveldb中&#xff0c;数字的存储统一采用小端序&#xff0c;通过对数字编码和压缩&#xff0c;节省了存储空间。 变长编码 小端序中&#xff0c;每个字节的最低位存储状态&#xff0c;其余7位存储数据。 status状态值说明&#xff1a; 1&#xff1a;该字节不是当前数字最后…

《Few-shot Object Counting and Detection》CVPR2022

概述 摘要&#xff1a; 论文提出了一个新的任务——少量样本目标计数和检测&#xff08;Few-shot Object Counting and Detection, FSCD&#xff09;。在这项任务中&#xff0c;研究者们旨在通过给定少量目标类别的示例边界框来计数和检测图像中所有目标对象。这项任务与少量样…

Your connection to this site is not secure

chrome 打开某一个网站的网页地址栏提示Your connection to this site is not secure,同一个网站的其它地址栏打开不会 无效的方案 浏览器地址栏输入: chrome://flags 找到下边的选项&#xff0c;从Default改为Disabled即可成功解决 亲测这个方法不行 解决方案 点击右上角的3个…

力扣每日一题 一个小组的最大实力值 线性DP

Problem: 2708. 一个小组的最大实力值 &#x1f468;‍&#x1f3eb; 灵神题解 class Solution {public long maxStrength(int[] nums) {// 初始化mn和mx为第一个元素的值long mn nums[0];long mx nums[0];// 从第二个元素开始遍历数组for (int i 1; i < nums.length; i…

vue项目生成插件的LICENSE文件

一、安装license-webpack-plugin npm install --save-dev license-webpack-plugin 二、添加webpack配置 const {LicenseWebpackPlugin} require(license-webpack-plugin)module.exports {configureWebpack: {plugins: [new LicenseWebpackPlugin()]} }三、执行npm run buil…