java并发编程 SynchronousQueue详解

文章目录

  • 1 SynchronousQueue是什么
  • 2 核心属性详解
  • 3 核心方法详解
    • 3.1 transfer(E e, boolean timed, long nanos)
      • 3.1.1 TransferStack实现
      • 3.1.2 TransferQueue实现
    • 3.2 外部方法
      • 3.2.1 put(E e)
      • 3.2.2 offer(E e)
      • 3.2.3 take()
      • 3.2.4 poll()
  • 4 总结


java 并发编程系列文章目录

1 SynchronousQueue是什么

在java的注释上写着:一种阻塞队列,其中每个插入操作都必须等待另一个线程执行相应的移除操作,反之亦然。元素的size()方法返回一定是0,就是内部元素不可见,你要么阻塞添加元素,要么阻塞获取元素,获取到元素,返回,提供元素的线程也返回。如果非阻塞,那么只有当前队列里有等待transfer的线程和你的mode不同才会成功。

2 核心属性详解

通过内部类实现数据传输功能,有两个实现,即公平和非公平,对应的数据结构是queue 和 stack

	abstract static class Transferer<E> {//对于生成者 E是提交的元素,不为null,消费者是null, 剩下两个参数表示是否是有阻塞,和超时时间abstract E transfer(E e, boolean timed, long nanos);}//...省略其他

3 核心方法详解

3.1 transfer(E e, boolean timed, long nanos)

3.1.1 TransferStack实现

基于stack栈的数据结构,每次都是设置head,然后按照特性,如果不带时间的情况,transfer数据如果head没有,说明没有其他线程在等待transfer,所以直接失败
如果带有时间的,会park住,等待其他transfer的来匹配唤醒。整体流程就是这样

    E transfer(E e, boolean timed, long nanos) {SNode s = null;//数据为null就表示来拿数据的,否则就是put数据的int mode = (e == null) ? REQUEST : DATA;for (;;) {SNode h = head;//如果此时是空,或者当前头结点的mode和自己相同if (h == null || h.mode == mode) {//1. 需要timed 但是nanos 是非正数,那就不需要等待,直接返回,其实就是必定不成功,因为h.mode == mode,不一样的时候h == null 没法匹配其他线程的数据//此时会清理match == this的head,就是匹配失败的nodeif (timed && nanos <= 0) {if (h != null && h.isCancelled())casHead(h, h.next);     // pop cancelled nodeelsereturn null;} //此时是非timed 或者 timed 且 nanos > 0的 因为此时是stack结构,所以设置head为自己else if (casHead(h, s = snode(s, e, h, mode))) {//设置成功 获取Node 如果返回的是自己,说明获取失败 下面会描述该方法SNode m = awaitFulfill(s, timed, nanos);if (m == s) {//这个方法就是重新设置headclean(s);return null;}//获取数据成功了,重新设置headif ((h = head) != null && h.next == s)casHead(h, s.next);//返回对应的数据return (E) ((mode == REQUEST) ? m.item : s.item);}} //此时h != null 或者 mode不相同//此时head 没有被占用else if (!isFulfilling(h.mode)) { //对match == this去除掉if (h.isCancelled())           casHead(h, h.next);  //设置head       else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {//设置成功for (;;) {SNode m = s.next;if (m == null) {casHead(s, null);s = null;break;}SNode mn = m.next;//尝试匹配 把m.match设置成s 此时会唤醒对应的阻塞线程if (m.tryMatch(s)) {casHead(s, mn); return (E) ((mode == REQUEST) ? m.item : s.item);} else                  s.casNext(m, mn);}}} else {//此时head是FULFILLING状态 那就拿head.next去尝试匹配,相同的原理                      SNode m = h.next;               if (m == null)                 casHead(h, null);  else {SNode mn = m.next;if (m.tryMatch(h)) casHead(h, mn); else                   h.casNext(m, mn);    }}}}//这个方法就是线程到这匹配数据 匹配不到就阻塞。整体逻辑是这个SNode awaitFulfill(SNode s, boolean timed, long nanos) {final long deadline = timed ? System.nanoTime() + nanos : 0L;Thread w = Thread.currentThread();//int spins = (shouldSpin(s) ?(timed ? maxTimedSpins : maxUntimedSpins) : 0);for (;;) {if (w.isInterrupted())s.tryCancel();SNode m = s.match;if (m != null)return m;if (timed) {nanos = deadline - System.nanoTime();if (nanos <= 0L) {s.tryCancel();continue;}}if (spins > 0)spins = shouldSpin(s) ? (spins-1) : 0;//此处以上代码就是判断超时 循环次数 节点是否匹配过,在一个cas + for循环每次都要验证数据的//设置等待的线程,之后会被其他线程来匹配的时候唤醒。唤醒是在tryMatchelse if (s.waiter == null)s.waiter = w; // establish waiter so can park next iterelse if (!timed)//阻塞当前线程LockSupport.park(this);else if (nanos > spinForTimeoutThreshold)//阻塞带有超时时间的LockSupport.parkNanos(this, nanos);}}

3.1.2 TransferQueue实现

只是数据结构改变而已,实现逻辑几乎不变

3.2 外部方法

3.2.1 put(E e)

放入一个元素,如果返回的是Null,按照transfer原理,是走到LockSupport.park(this); 即没匹配带数据就会阻塞,如果返回Null就是中断的情况所以会重置中断位且抛出中断异常

    public void put(E e) throws InterruptedException {if (e == null) throw new NullPointerException();if (transferer.transfer(e, false, 0) == null) {Thread.interrupted();throw new InterruptedException();}}

3.2.2 offer(E e)

因为timed == true 且nanos = 0 所以如果此时没有head 会立马返回

    public boolean offer(E e) {if (e == null) throw new NullPointerException();//只是返回成功或者失败return transferer.transfer(e, true, 0) != null;}

3.2.3 take()

timed == false 其实和put一样会进入LockSupport.park(this) 阻塞自己,此时会出现中断情况,所以会判断返回结果,是null重置中断位,抛出异常。

    public E take() throws InterruptedException {E e = transferer.transfer(null, false, 0);if (e != null)return e;Thread.interrupted();throw new InterruptedException();}

3.2.4 poll()

poll方法 timed == true nanos == 0 所以如果head == null 会直接返回,这个方法就是直接获取数据,返回结果 可能为null

    public E poll() {return transferer.transfer(null, true, 0);}

4 总结

利用transfer方法提供了两种实现,让多个线程之间可以去交换数据,它与其他队列的区别在于,不是用一个数据结构去永久的存储数据,这里你想把数据一定能给别人使用,只有阻塞等待别人来匹配,用offer的方式,此时head == null 就会立马失败返回null

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

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

相关文章

shell脚本之sed命令

shell脚本之sed命令 sed 命令的一些常用选项sed 命令的一些常用命令具体例子 sed 在 Shell 脚本中非常常用&#xff0c;可以用于文本替换、插入、删除等操作。 以下是 sed 命令的基本语法&#xff1a; sed [选项] 命令 [文件...]其中&#xff0c;选项是可选的&#xff0c;可以…

关于CMake多级目录/多个子目录/子目录文件调用另外子目录文件接口及清除CMake生成的中间文件的注意事项

1&#xff09;如果子目录代码文件相对独立&#xff0c;也就是没有引用其他子目录的文件&#xff0c;可以单独编译成库文件 上层CMakeLists.txt通过link_libraries()来添加这个库文件 2&#xff09;如果子目录代码引用了其他子目录的文件&#xff0c;建议在上一层编译(前提也是…

睿趣科技:抖音开店前期需要准备什么

抖音作为全球最受欢迎的短视频平台之一&#xff0c;已经成为了许多年轻人的创业和赚钱的机会。如果你计划在抖音上开店&#xff0c;那么在正式开业之前&#xff0c;有一些重要的准备工作是必不可少的。下面就是抖音开店前期需要准备的关键步骤和注意事项。 确定你的目标和产品&…

Matlab图像处理-三原色

三原色 根据详细的实验结果&#xff0c;人眼中负责颜色感知的细胞中约有65%对红光敏感&#xff0c;33%对绿光敏感&#xff0c;只有2%对蓝光敏感。正是人眼的这些吸收特性决定了所看到的彩色是一般所谓的原色红&#xff08;R&#xff09;、绿&#xff08;G&#xff09;和蓝&…

动态渲染 echarts 饼图(vue 2 + axios + Springboot)

目录 前言1. 项目搭建1.1. 前端1.2. 后端 2. 后端数据渲染前端2.1 补充1&#xff1a;在 vue 中使用 axios2.2. 补充2&#xff1a;Springboot 处理跨域问题2.3. 修改前端代码2.3.1 修改饼图样式2.3.2 调用后台数据渲染饼图2.3.3 改造成内外两个圈 前言 因为上文中提到的需求就是…

内网隧道代理技术(二十五)之 ICMP隧道反弹SHELL

ICMP隧道反弹SHELL ICMP隧道原理 由于ICMP报文自身可以携带数据,而且ICMP报文是由系统内核处理的,不占用任何端口,因此具有很高的隐蔽性。把数据隐藏在ICMP数据包包头的data字段中,建立隐蔽通道,可以实现绕过防火墙和入侵检测系统的阻拦。 ICMP隧道有以下的优点: ICMP…

腾讯云4核8G服务器选CVM还是轻量比较好?价格对比

腾讯云4核8G云服务器可以选择轻量应用服务器或CVM云服务器标准型S5实例&#xff0c;轻量4核8G12M服务器446元一年&#xff0c;CVM S5云服务器935元一年&#xff0c;相对于云服务器CVM&#xff0c;轻量应用服务器性价比更高&#xff0c;轻量服务器CPU和CVM有区别吗&#xff1f;性…

博客系统(升级(Spring))(四)(完)基本功能(阅读,修改,添加,删除文章)(附带项目)

博客系统 (三&#xff09; 博客系统博客主页前端后端个人博客前端后端显示个人文章删除文章 修改文章前端后端提取文章修改文章 显示正文内容前端后端文章阅读量功能 添加文章前端后端 如何使用Redis项目地点&#xff1a; 博客系统 博客系统是干什么的&#xff1f; CSDN就是一…

数字化转型对企业有哪些优势?

数字化转型为企业提供了众多优势&#xff0c;帮助他们在日益数字化的世界中保持竞争力、敏捷性和响应能力。以下是一些主要优势&#xff1a; 1.提高效率和生产力&#xff1a; 重复性任务和流程的自动化可以减少人为错误&#xff0c;并使员工能够专注于更具战略性的任务。简化…

Apache Linki 1.3.1+DataSphereStudio+正常启动+微服务+端口号

我使用的是一键部署容器化版本&#xff0c;官方文章 默认会启动6个 Linkis 微服务&#xff0c;其中下图linkis-cg-engineconn服务为运行任务才会启动,一共七个 LINKIS-CG-ENGINECONN:38681 LINKIS-CG-ENGINECONNMANAGER:9102 引擎管理服务 LINKIS-CG-ENTRANCE:9104 计算治理入…

Vue开发小注意点

改bug 更改了配置项啥的&#xff0c;保存刷新发现没变&#xff0c;那就重启项目&#xff01;&#xff01;&#xff01;&#xff01; binding.value 和 e.target.value binding.value Day5 指令的值 e.target.value Day4 表单组件封装 binding.value 和 e.target.valu…

plt函数显示图片 在图片上画边界框 边界框坐标转换

一.读取图片并显示图片 %matplotlib inline import torch from d2l import torch as d2l读取图片 image_path ../data/images/cat_dog_new.jpg # 创建画板 figure d2l.set_figsize() image d2l.plt.imread(image_path) d2l.plt.imshow(image);二.给出一个(x左上角,y左上角,…

Flask 使用 JWT(三)flask-jwt-extended

如果想要在 flask 中使用 JWT ,推荐使用 flask-jwt-extended 插件。 使用 pip 安装这个扩展插件的最简单方法是: pip install flask-jwt-extended基本使用 在接下来的案例中,我们看一下基本使用。我们可以使用 create_access_token() 函数用来生成实际的 JWT token。@jwt_r…

K8S之使用yaml格式定义pod

mysql-pod.yaml # overView: # 1. web服务与db打包放在同一个pod中&#xff0c;本地通过localhost来访问&#xff0c;并附带存活性/可用性检测 # 2. 补充重启策略/镜像拉去策略 # 3. 对容器资源进行限制apiVersion: apps/v1 kind: Pod metadata:name: pub-oanamespace: hunte…

__declspec(novtable) 在C++

__declspec(novtable) 在C中接口中广泛应用. 不容易看到它是因为在很多地方它都被定义成为了宏. 比如说ATL活动模板库中的ATL_NO_VTABLE, 其实就是__declspec(novtable). __declspec(novtable) 就是让类不要有虚函数表以及对虚函数表的初始化代码, 这样可以节省运行时间和空间.…

服务注册与服务发现

服务注册与服务发现 Eureka的架构 Eureka客户端&#xff1a;使用了EnableEurekaClient注解的应用服务&#xff0c;如订单服务等&#xff0c;甚至Eureka本身也是一个客户端 Eureka服务端&#xff1a;使用了EnableEurekaServer注解的应用服务&#xff0c;该服务提供了注册表以及…

使用Git把项目上传到Gitee的详细步骤

1.到Git官网下载并安装 2.到Gitee官网进行注册&#xff0c;然后在Gitee中新建一个远程仓库 3.设置远程仓库的参数 4.返回Gitee查看仓库是否生成成功 5.新建一个文件夹作为你的本地仓库 6.将新建好的文件夹初始化成本地仓库 第一步&#xff1a;右键点击刚创建的本地仓库&#…

小程序实现一个 倒计时组件

小程序实现一个 倒计时组件 需求背景 要做一个倒计时&#xff0c;可能是天级别&#xff0c;也可能是日级别&#xff0c;时级别&#xff0c;而且每个有效订单都要用&#xff0c;就做成组件了 效果图 需求分析 需要一个未来的时间戳&#xff0c;或者在服务度直接下发一个未来…

NeuroFlash:AI文章写作与生成工具

【产品介绍 ​ 】 名称 NeuroFlash 上线时间 2015 具体描述 Neuroflash是一款基于人工智能的文本和图像生成器&#xff0c;可以帮助用户快速创建高质量的内容。Neuroflash拥有超过100种短文和长文的文本类型&#xff0c;涵盖了各种营销场景和需求。只需要输入简单的指示&#…

【Excel函数】Trim函数删除前后多余的空格

Excel 中的 TRIM 函数用于删除文本字符串两端多余的空格&#xff0c;只保留字符串内部的空格。这对于清理和规范化文本数据非常有用。 在使用Excel中使用TRIM可以删除内容前面和后面的空格字符&#xff0c;Trim的语法规则如下&#xff1a; A2trim(Text) text&#xff1a;要进…