synchronousqueue场景_java中SynchronousQueue的核心方法

synchronousqueue场景_java中SynchronousQueue的核心方法我们之前提过SynchronousQueue入队和出队的两种方法,其实它们都依托transfer方法得以实现。相比较而言,transfer可以同步进行入队和出队的操作,是SynchronousQueue中最重要的核心方法。下面我们就transfer概念、使用场景,以及在代码中增减元素的实例带来全面介绍。1.transfer概念进行匹配交换数据,SynchronousQueue内部使用Transfe…

大家好,又见面了,我是你们的朋友全栈君。

synchronousqueue场景_java中SynchronousQueue的核心方法

我们之前提过SynchronousQueue入队和出队的两种方法,其实它们都依托transfer方法得以实现。相比较而言,transfer可以同步进行入队和出队的操作,是SynchronousQueue中最重要的核心方法。下面我们就transfer概念、使用场景,以及在代码中增减元素的实例带来全面介绍。

1.transfer概念

进行匹配交换数据,SynchronousQueue内部使用Transferer来交换元素。

(1) 传入元素e,是生产者(put方法),

(2) 传入null,是消费者(take方法)。

2.使用场景

(1)当调用这个方法时,如果队列是空的,或者队列中的节点和当前的线程操作类型一致(如当前操作是 put 操作,而队列中的元素也都是写线程)。这种情况下,将当前线程加入到等待队列即可。

(2)如果队列中有等待节点,而且与当前操作可以匹配(如队列中都是读操作线程,当前线程是写操作线程,反之亦然)。这种情况下,匹配等待队列的队头,出队,返回相应数据。

3.实例// TransferStack.transfer()方法

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

SNode s = null; // constructed/reused as needed

// 根据e是否为null决定是生产者还是消费者

int mode = (e == null) ? REQUEST : DATA;

// 自旋+CAS,熟悉的套路,熟悉的味道

for (;;) {

// 栈顶元素

SNode h = head;

// 栈顶没有元素,或者栈顶元素跟当前元素是一个模式的

// 也就是都是生产者节点或者都是消费者节点

if (h == null || h.mode == mode) {  // empty or same-mode

// 如果有超时而且已到期

if (timed && nanos <= 0) {      // can’t wait

// 如果头节点不为空且是取消状态

if (h != null && h.isCancelled())

// 就把头节点弹出,并进入下一次循环

casHead(h, h.next);     // pop cancelled node

else

// 否则,直接返回null(超时返回null)

return null;

} else if (casHead(h, s = snode(s, e, h, mode))) {

// 入栈成功(因为是模式相同的,所以只能入栈)

// 调用awaitFulfill()方法自旋+阻塞当前入栈的线程并等待被匹配到

SNode m = awaitFulfill(s, timed, nanos);

// 如果m等于s,说明取消了,那么就把它清除掉,并返回null

if (m == s) {               // wait was cancelled

clean(s);

// 被取消了返回null

return null;

}

// 到这里说明匹配到元素了

// 因为从awaitFulfill()里面出来要不被取消了要不就匹配到了

// 如果头节点不为空,并且头节点的下一个节点是s

// 就把头节点换成s的下一个节点

// 也就是把h和s都弹出了

// 也就是把栈顶两个元素都弹出了

if ((h = head) != null && h.next == s)

casHead(h, s.next);     // help s’s fulfiller

// 根据当前节点的模式判断返回m还是s中的值

return (E) ((mode == REQUEST) ? m.item : s.item);

}

} else if (!isFulfilling(h.mode)) { // try to fulfill

// 到这里说明头节点和当前节点模式不一样

// 如果头节点不是正在撮合中

// 如果头节点已经取消了,就把它弹出栈

if (h.isCancelled())            // already cancelled

casHead(h, h.next);         // pop and retry

else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {

// 头节点没有在撮合中,就让当前节点先入队,再让他们尝试匹配

// 且s成为了新的头节点,它的状态是正在撮合中

for (;;) { // loop until matched or waiters disappear

SNode m = s.next;       // m is s’s match

// 如果m为null,说明除了s节点外的节点都被其它线程先一步撮合掉了

// 就清空栈并跳出内部循环,到外部循环再重新入栈判断

if (m == null) {        // all waiters are gone

casHead(s, null);   // pop fulfill node

s = null;           // use new node next time

break;              // restart main loop

}

SNode mn = m.next;

// 如果m和s尝试撮合成功,就弹出栈顶的两个元素m和s

if (m.tryMatch(s)) {

casHead(s, mn);     // pop both s and m

// 返回撮合结果

return (E) ((mode == REQUEST) ? m.item : s.item);

} else                  // lost match

// 尝试撮合失败,说明m已经先一步被其它线程撮合了

// 就协助清除它

s.casNext(m, mn);   // help unlink

}

}

} else {                            // help a fulfiller

// 到这里说明当前节点和头节点模式不一样

// 且头节点是正在撮合中

SNode m = h.next;               // m is h’s match

if (m == null)                  // waiter is gone

// 如果m为null,说明m已经被其它线程先一步撮合了

casHead(h, null);           // pop fulfilling node

else {

SNode mn = m.next;

// 协助匹配,如果m和s尝试撮合成功,就弹出栈顶的两个元素m和s

if (m.tryMatch(h))          // help match

// 将栈顶的两个元素弹出后,再让s重新入栈

casHead(h, mn);         // pop both h and m

else                        // lost match

// 尝试撮合失败,说明m已经先一步被其它线程撮合了

// 就协助清除它

h.casNext(m, mn);       // help unlink

}

}

}

}

// 三个参数:需要等待的节点,是否需要超时,超时时间

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 (;;) {

// 当前线程中断了,尝试清除s

if (w.isInterrupted())

s.tryCancel();

// 检查s是否匹配到了元素m(有可能是其它线程的m匹配到当前线程的s)

SNode m = s.match;

// 如果匹配到了,直接返回m

if (m != null)

return m;

// 如果需要超时

if (timed) {

// 检查超时时间如果小于0了,尝试清除s

nanos = deadline – System.nanoTime();

if (nanos <= 0L) {

s.tryCancel();

continue;

}

}

if (spins > 0)

// 如果还有自旋次数,自旋次数减一,并进入下一次自旋

spins = shouldSpin(s) ? (spins-1) : 0;

// 后面的elseif都是自旋次数没有了

else if (s.waiter == null)

// 如果s的waiter为null,把当前线程注入进去,并进入下一次自旋

s.waiter = w; // establish waiter so can park next iter

else if (!timed)

// 如果不允许超时,直接阻塞,并等待被其它线程唤醒,唤醒后继续自旋并查看是否匹配到了元素

LockSupport.park(this);

else if (nanos > spinForTimeoutThreshold)

// 如果允许超时且还有剩余时间,就阻塞相应时间

LockSupport.parkNanos(this, nanos);

}

}

// SNode里面的方向,调用者m是s的下一个节点

// 这时候m节点的线程应该是阻塞状态的

boolean tryMatch(SNode s) {

// 如果m还没有匹配者,就把s作为它的匹配者

if (match == null &&

UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {

Thread w = waiter;

if (w != null) {    // waiters need at most one unpark

waiter = null;

// 唤醒m中的线程,两者匹配完毕

LockSupport.unpark(w);

}

// 匹配到了返回true

return true;

}

// 可能其它线程先一步匹配了m,返回其是否是s

return match == s;

}

以上就是java中SynchronousQueue的核心方法,相信已经本篇对于transfer方法的学习,在有关入队和出队的操作上就会进行的比较顺利,学会后一定要加强这方面使用方法的记忆。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/152135.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 好用的Redis客户端操作工具[通俗易懂]

    好用的Redis客户端操作工具[通俗易懂]日常开发过程中,项目常常都会使用Redis来做缓存或者Session服务器,为了更直观方便,开发者常常会使用一些可视化工具,如RedisDesktopManager、RedisClent等,但界面UI做得不尽人意,作为当今时代,对软件的UI还是有所期待的,今天给大家分享一款,高颜值、功能强大的Redis客户端工具。AnotherRedisDesktopManager一个更快、更好、更稳定的redis桌面管理工具,可以运行于Linux、Windows、Mac三大平台,并且当加载大数量的key不.

    2022年6月5日
    32
  • nessus中文版使用教程_svn中文使用教程

    nessus中文版使用教程_svn中文使用教程https://www.wangan.com/docs/nessus

    2022年10月10日
    3
  • 1521端口 mysql_Linux开放1521端口允许网络连接Oracle Listener

    1521端口 mysql_Linux开放1521端口允许网络连接Oracle Listener症状:1.TCP/IP连接是通的。可以用ping命令测试。2.服务器上OracleListener已经启动。lsnrctlstatus查看listener状态lsnrctlstart启动Oraclelistener3.客户端得到的错误信息通常是:ORA-12170:TNS:连接超时这时,我们基本可以肯定是服务器没有开放1521端口(假设你用默认设置)解决…

    2022年5月1日
    115
  • C++旅游管理系统

    C++旅游管理系统C++旅游管理系统https://download.csdn.net/download/fuck11111/3364686

    2022年6月9日
    38
  • 机器学习中【回归算法】详解

    机器学习中【回归算法】详解关注微信公众号【Microstrong】,我写过四年Android代码,了解前端、熟悉后台,现在研究方向是机器学习、深度学习!一起来学习,一起来进步,一起来交流吧!本文同步更新在我的微信公众号里,地址:https://mp.weixin.qq.com/s?__biz=MzI5NDMzMjY1MA==&amp;mid=2247483935&amp;idx=1&amp;sn=5e1c55c76…

    2022年8月21日
    5
  • 向量的范数和矩阵的范数_矩阵范数与向量范数相容是什么意思

    向量的范数和矩阵的范数_矩阵范数与向量范数相容是什么意思矩阵是什么?我们都知道映射指的是一个空间Rm\mathbb{R}^mRm到另一个空间Rn\mathbb{R}^nRn的变换关系,狭义的函数其实是映射的一种特例,特指实数集间R1\mathbb{R}^1R1的映射关系。在所有映射中,我们最常见的是线性映射,对这种线性映射关系,我们是用矩阵来刻画,比如我们要将一个向量x∈Rmx\in\mathbb{R}^mx∈Rm映射到另外一个空间Rn\…

    2025年11月29日
    11

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号