BlockingQueue二

news2024/12/22 14:25:30

接着上篇BlockingQueue没讲完的

LinkedTransferQueue

LinkedTransferQueue是一个由链表结构组成的无界阻塞队列,相对于其它阻塞队列,LinkedBlockingQueue可以算是LinkedBlockingQueue与SynhronoousQueue结合,LinkedtransferQueue是一种无界阻塞队列,底层基于单链表实现,其内部结构分为数据节点、请求节点,基于CAS无锁算法实现

与前面类似不再赘述

        final boolean isData;   
        volatile Object item;  
        volatile Node next;
        volatile Thread waiter;

其中节点操作过程类似于SynchronousQueue
在这里插入图片描述
在这里插入图片描述
与SynchronousQueue有区别的是这个可以设置是否阻塞当前线程

NOW=0表示即时操作(可能失败),即不会阻塞调用线程
poll(获取并移除首元素,如果队列为空,直接返回null)
tryTransfer(尝试将元素传递给消费者,如果没有等待的消费者则立即返回false,也不会将元素入队)

ASYNC=1表示异步操作(必然成功)
xfer被操作线程调用时,无论xfer操作过程多久完成,调用者都不会阻塞等待
offer,put,add(插入指定元素到队尾,由于是无界队列,所以会立即返回true)

SYNC=2表示同步操作(阻塞调用线程)
只有xfer操作过程达到了调用线程所期望的结果,调用者才会继续向下执行

TIMED=3表示限时同步操作

PriorityBlockingQueue

优先级队列,里面是数组,但是数组与普通数组不一样,里面的数组维护了一颗堆的二叉树
默认大小为11,但是这个可以扩容

	//默认容量
	private static final int DEFAULT_INITIAL_CAPACITY = 11;
	//最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	//存储数据
    private transient Object[] queue;
	//元素个数
    private transient int size;
	//比较
    private transient Comparator<? super E> comparator;
	//锁
    private final ReentrantLock lock;
	//等待
    private final Condition notEmpty;
	
    private transient volatile int allocationSpinLock;

扩容

如果容量小于64的时候,扩容为原来两倍+2;
如果容量大于64的时候,扩容为原来1.5倍

    private void tryGrow(Object[] array, int oldCap) {
        lock.unlock(); //扩容前先释放锁(扩容可能会费时,先让出锁,让出队线程可以正常操作)
        Object[] newArray = null;
        if (allocationSpinLock == 0 &&
            UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
                                     0, 1)) {//通过CAS操作确保只有一个线程可以扩容
            try {
                int newCap = oldCap + ((oldCap < 64) ?
                                       (oldCap + 2) : 
                                       (oldCap >> 1));
                if (newCap - MAX_ARRAY_SIZE > 0) {//大于当前最大容量则可能溢出
                    int minCap = oldCap + 1;
                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)//扩大一个元素也溢出或者超过最大容量则抛出异常
                        throw new OutOfMemoryError();
                    newCap = MAX_ARRAY_SIZE;//扩容后如果超过最大容量,则只扩大到最大容量
                }
                if (newCap > oldCap && queue == array)
                    newArray = new Object[newCap];//根据最新容量初始化一个新数组
            } finally {
                allocationSpinLock = 0;
            }
        }
        if (newArray == null) //如果是空,说明前面CAS失败,有线程在扩容,让出CPU
            Thread.yield();
        lock.lock();//这里重新加锁是确保数组复制操作只有一个线程能进行
        if (newArray != null && queue == array) {
            queue = newArray;
            System.arraycopy(array, 0, newArray, 0, oldCap);//将旧的元素复制到新数组
        }
    }

添加元素

添加元素不会阻塞线程,因为该队列是一个无界队列,因为可以扩容,所以添加元素不会出现阻塞

    public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);
        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftUpComparable(n, e, array);
            else
                siftUpUsingComparator(n, e, array, cmp);
            size = n + 1;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }

取出元素

取出元素需要判断是否为空,如果为空则需要等待,不然直接返回

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = dequeue()) == null)
                notEmpty.await();
        } finally {
            lock.unlock();
        }
        return result;
    }

    private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }

里面主要堆的上浮与下沉

另一个上浮的方法除了比较器不同以外其它都类似,所以就讲这一个
假设我们构造的是小根堆

    private static <T> void siftUpComparable(int k, T x, Object[] array) {
    	// 其中k就是当前放的末尾的位置
        Comparable<? super T> key = (Comparable<? super T>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1; //找到其父节点
            Object e = array[parent];
            if (key.compareTo((T) e) >= 0) //如果当前放入的值大于其父节点则跳出,否则继续
                break;
            // 到这里说明当前放入的值小于其父节点,与父节点交换位置,并且k变为父节点的位置
            array[k] = e; 
            k = parent;
        }
        array[k] = key;
    }
 private static <T> void siftDownComparable(int k, T x, Object[] array,int n) {
        if (n > 0) {
            Comparable<? super T> key = (Comparable<? super T>)x;
            int half = n >>> 1;           
            while (k < half) {
                int child = (k << 1) + 1;   
                Object c = array[child];
                int right = child + 1;
                if (right < n &&
                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
                    c = array[child = right];   // 如果右孩子比左孩子小,则弄成右孩子
                if (key.compareTo((T) c) <= 0) //如果传入的值小于孩子则退出
                    break;
                array[k] = c;
                k = child;
            }
            array[k] = key;
        }
    }

LinkedBlockingDeque

与LinkedBlockingQueue类似,只是这个是可以从两端存取,而LinkedBlockingQueue是单链表只能从一边存取,同时LinkedBlockingDeque只有一把锁,如果两把锁的话容易造成下标出错

DelayQueue

其中内部也是由一个PriorityQueue维护一个优先队列

add

    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            q.offer(e);
            if (q.peek() == e) {
                leader = null;
                available.signal();
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

take

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null)
                    available.await();  //如果队列为空阻塞
                else {
                    long delay = first.getDelay(NANOSECONDS);
                    if (delay <= 0)
                        return q.poll(); //如果到期了就返回
                    first = null; // don't retain ref while waiting
                    if (leader != null) // 没有到期且leader不为空,等待
                        available.await();
                    else { //头节点为空,设置当前线程为头节点
                        Thread thisThread = Thread.currentThread();
                        leader = thisThread;
                        try {
                            available.awaitNanos(delay);
                        } finally {
                            if (leader == thisThread)
                                leader = null;
                        }
                    }
                }
            }
        } finally {
            if (leader == null && q.peek() != null)
                available.signal();
            lock.unlock();
        }
    }

Leader-Follower线程模型

在Leader-follower线程模型中每个线程有三种模式:

leader:只有一个线程成为leader,如DelayQueue如果有一个线程在等待元素到期,则其他线程就会阻塞等待
follower:会一直尝试争抢leader,抢到leader之后才开始干活
processing:处理中的线程

感谢这位大佬 双子孤狼的博客

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

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

相关文章

Unity学习笔记--详细介绍CacheServer、部署方法、以及在Unity中的位置

目录前言CacheServer是什么&#xff1f;解决了什么问题&#xff1f;其他知识点在哪里找到Cache Server&#xff1f;怎么部署CacheServer&#xff1f;Unity什么时候需要生成内部文件&#xff1f;CacheServer缓存的是什么&#xff1f;随着越来越多的资源被导入和存储&#xff0c;…

实战-COVID-19-KSH(html+ python +django +爬虫 +pyecharts 实时疫情动态)内附MySQL详细安装配置教程

GitHub代码 Windows10 python3.7 一、MySQL配置 1.官网下载地址 2.配置初始化文件my.ini 解压后在根目录下创建my.ini文件&#xff08;建立.txt-修改扩展名为.int即可&#xff09; 打开my.ini文件&#xff0c;输入以下内容&#xff08;注意需要改动2处&#xff09;&#x…

求一个网页设计作业——个人博客(HTML+CSS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

9.Springboot整合Security很全

1.什么是Security SpringSecurity是基于Spring AOP和Servlet过滤器的安全框架。 它提供全面的安全性解决方案&#xff0c;同时在Web 请求级和方法调用级处理身份确认和授权。 2.Spring Security核心功能&#xff1f; &#xff08;1&#xff09;认证&#xff08;你是谁&…

薪资25k,从华为外包测试“跳”入字节,说说我转行做测试的这5年...

转行测试5年了 当时因为家里催促就业&#xff0c;在其中一个室友的内推下进入了一家英语教培机构&#xff0c;前期上班和工资都还算满意&#xff0c;甚至觉得自己找到了一份很稳定的工作了&#xff0c;可是好景不长&#xff0c;“双减政策”的到来&#xff0c;让公司的经济遭受…

Linux进程间通讯技术

Linux进程间通讯 文章目录Linux进程间通讯1.进程通讯基本认知1.1 进程通讯的概念1.2 进程通讯的目的1.3 进程通讯的本质1.4 进程通讯的分类2.管道技术基本认知2.1 管道的概念2.2 为什么需要管道2.3 管道的四个特点2.4 管道的四种情况2.5 管道的大小获取2.6 命名管道与匿名管道的…

MyBatis-Plus条件构造器[常用的模糊查询、排序查询、逻辑查询和指定字段查询案例]

系列文章目录 Mybatis-Plus知识点[MyBatisMyBatis-Plus的基础运用]_心态还需努力呀的博客-CSDN博客 Mybatis-PlusSpringBoot结合运用_心态还需努力呀的博客-CSDN博客MyBaits-Plus中TableField和TableId用法_心态还需努力呀的博客-CSDN博客 MyBatis-Plus中的更新操作&#x…

2.2 反相放大器、高输入电阻反相放大器、反相高压放大器

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

【cocos源码学习】解决cocos2d-x-4.0 Android Demo构建遇到的问题

环境 硬件&#xff1a;macbook pro 四核Intel Core i7系统&#xff1a;macOS Big Sur 11.4.2、 xcode Version 13.1 、cmake 3.20.5软件&#xff1a;iterm2 Build 3.4.8、zsh 5.8、Android Studio Dolphin | 2021.3.1cocos2d-x v4 &#xff1a; 官方下载压缩包 http://cocos2d…

目标检测算法——YOLOv5/YOLOv7改进之结合特征提取网络RFBNet(涨点明显)

>>>深度学习Tricks,第一时间送达<<< 🚀🚀🚀NEW!!!魔改YOLOv5/v7目标检测算法来啦 ~ 计算机视觉——致力于目标检测领域科研Tricks改进与推荐 | 主要包括Backbone、Neck、Head、普通注意力机制、自注意力机制Transformer、Swin Transformer v2,各…

Java中Set集合的使用和底层原理

文章目录Set系列集合介绍Set集合概述HashSet无序原理Set集合对象去重LinkedHashSetTreeSet排序规则Set系列集合介绍 Set集合概述 Set系列集合特点: 无序&#xff1a;存取数据的顺序是不一定的, 当数据存入后, 集合的顺序就固定下来了 不重复&#xff1a;可以去除重复 无索引&…

HTML期末学生大作业:中华传统文化【苏绣手工艺】带psd设计图(15页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

线程的基本操作以及线程的状态

目录 &#x1f433;今日良言:得之坦然&#xff0c;失之淡然&#xff0c;争取必然&#xff0c;顺其自然。 &#x1f42f;一、线程的基本操作 &#x1f42d;1.线程的创建 &#x1f42d;2.线程的中断 &#x1f42d;3.线程的等待 &#x1f42d;4.获取线程实例 &#x1f42d;…

[附源码]计算机毕业设计学分制环境下本科生学业预警帮扶系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【POJ No. 3264】区间最值差 Balanced Lineup

【POJ No. 3264】区间最值差 Balanced Lineup 北大OJ 题目地址 其实这道题 之前也做过一次了 http://t.csdn.cn/0YZgC 不过上次是用ST 做的。这次换做 分块来实现。 【题意】 每天挤奶时&#xff0c;约翰的N 头奶牛&#xff08;1≤N≤50,000&#xff09;都以相同的顺序排队…

【网络工程】7、实操-万达酒店综合项目(一)

接上篇《6、防火墙介绍及配置实操》 之前我们讲解了防火墙的基础知识以及相应的实操案例&#xff0c;本篇我们结合之前的交换机、路由器及防火墙的知识&#xff0c;进行一个酒店网络项目的实战。 本篇主要介绍一下酒店网络项目的整体需求文档。 一、项目背景 为规范万达美华…

tensorflow fashion_mnist数据集模型训练及预测

✨ 博客主页&#xff1a;小小马车夫的主页 ✨ 所属专栏&#xff1a;Tensorflow 文章目录前言一、环境二、fashion_mnist数据集介绍三、fashion_mnist数据集下载和展示四、数据预处理五、构建模型和训练模型六、模型预测总结前言 前面介绍mnist手写数字集训练&#xff0c;本文对…

自制肥鲨HDO2电源降压延长线,支持3S~6S动力电池

自制肥鲨HDO2电源降压延长线&#xff0c;支持3S~6S动力电池1. 问题源由2. 破题思路2.1 10元大钞搞定2.2 两个毛爷爷搞定3. 解决方案4. 最终延长线产出4.1 裸照4.2 成品5. 花絮1. 问题源由 源由&#xff1a; 电池盒电源线接触不良。 肥鲨眼镜的电源盒问题由来已久&#xff0c;…

SecureCRT隧道,跳板机+端口转发,内网穿透

背景 ServerA(Linux系统)&#xff1a; 内网&#xff1a;192.168.111.201 公网&#xff1a;10.121.8.88&#xff08;虚构的ip方便理解&#xff09; ServerB&#xff1a; 内网&#xff1a;192.168.111.202 本机&#xff1a; 安装有SecureCRT软件 注意上图中的箭头。箭头指向可…

Android动画——使用动画启动Activity

1、使用动画启动Activity概述 我们在Android开发应用时&#xff0c;会遇到一个页面跳转到另一个页面的情况&#xff0c;这时候我们如果使用动画过渡会使得页面更加的流畅。这是一个滑动式的进入和退出的动画可以看到Android的过渡动画可以在不同状态之间建立视觉联系。您可以为…