java 手写阻塞队列_java并发编程之深入学习Concurrent包(十二,阻塞队列.3)

引言:

上两章中,我们一起学习了阻塞队列中的ArrayBlockingQueue,LinkedBlokingQueue和PriorityBlockingQueue和DelayQueue,本章,我们一起学习一下SynchronousQueue类。

SynchronousQueue 是同步阻塞队列类。队列中的容器使用栈和队列来实现,分别实现“非公平”和“公平”模式的同步队列。

SynchronousQueue简介:

同步阻塞队列,队列(或栈)内部只能包含少量元素,且插入元素的线程需要阻塞到接收元素的线程到来才能执行完成,反之亦然。

SynchronousQueue源码分析:

SynchronousQueue实现了两个内部类:TransferStack和TransferQueue类,基本所有操作都是由这两个类来处理,我们主要介绍的也是两个类的内容。


一,TransferStack类(非公平模式):

用于“非公平”模式,按照LIFO(后进先出)顺序存储元素的模式。


1.1 TransferStack类的基本元素

如下代码所示,SNode是构成栈的基础结构,由next,match,waiter,item,mode组成,分别表示下一个节点,匹配节点,请求的线程,数据的内容(如果是消费方则为null),节点模式。

其中mode(节点模式)主要有三种,如下:

static final int REQUEST= 0;//消费方的节点,表示在此请求一个数据

static final int DATA= 1;//生产方的节点,表示在提供一个数据

static final int FULFILLING= 2;//表示已经本节点已经和对应节点匹配上,马上要出栈

如图,REQUEST和DATA是消费方和生产方的请求节点,FULFILLING则表示一对已匹配的节点:

a6299a03d42c01288308595d67a761c8.png

static final class SNode {

volatile SNode next; // next node in stack

volatile SNode match; // the node matched to this

volatile Thread waiter; // to control park/unpark

Object item; // data; or null for REQUESTs

int mode;

boolean casNext(SNodecmp, SNode val) {

return cmp == next &&

UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);

}

//tryMatch方法用于匹配s与本节点,看是否匹配,如果匹配,则将等待线程的阻塞取消。

boolean tryMatch(SNode s) {

if(match == null &&

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

Thread w = waiter;

if(w != null) {

waiter = null;

LockSupport.unpark(w);

}

return true;

}

return match == s;

}

// 节点取消,将match指向自身

void tryCancel() {

UNSAFE.compareAndSwapObject(this, matchOffset, null, this);

}

//判断是否是已取消的节点

boolean isCancelled() {

returnmatch == this;

}

}

volatile SNode head; //指向栈顶的节点


1.2 入队/出队操作逻辑

因出队/入队操作都使用transfer方法,直接对transfer方法进行分析即可。

如下代码所示,transfer方法将栈中的情况分为三种:

1.2.1 当前传入的模块是域栈顶模块相同(或者栈为空也是一样)。如下图

则当前节点入栈,等待匹配到对应的节点

c79aa2d9fe007205712fe6e6913dec0d.png

1.2.2 当前传入的模块与栈顶模块匹配,达成交付操作。如下图

将一个FULFILLING节点入栈,找到对应的匹配节点,并将它们出栈

510d56bb24f79a13b116aff2529aad61.png

1.2.3 当前栈顶的模块是匹配模块需要删除。如下图

找到对应的匹配节点,并将它们出栈

26535447f6a314a7776f2f17da1e0c68.png

代码如下所示:

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

SNodes = null; // constructed/reused as needed

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

for (;;) {

SNode h = head;

if(h == null || h.mode == mode) { //情况1

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

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

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

else

return null;

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

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

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

clean(s);

return null;

}

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

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

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

}

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

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

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

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

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

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;

if (m.tryMatch(s)) //情况2

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

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

} else // lost match

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

}

}

} else { //情况3 help a fulfiller

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

if(m == null) casHead(h, null);

else {

SNode mn = m.next;

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

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

else // lost match

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

}

}

}

}

1、线程data1执行情况1,由于当前没有配对的消费方线程,所以data1线程入栈,自旋后睡眠等待

2、线程data2再次执行了情况1,data2线程入栈,自旋一小会后睡眠等待。

3、来了一个线程req1,执行了情况2,发现栈顶为data2线程,互相匹配成功,会先把req1线程入栈,然后req1线程循环执行匹配put2线程逻辑,把栈顶指针直接指向 req1线程,就是将data2和req1出栈。

4、再来一个线程req2,执行情况2操作,req2线程入栈,在循环中匹配data1线程,最终全部匹配完毕,栈变为空,恢复初始状态。


二,TransferQueue类(公平模式):

用于“公平”模式,按照FIFO(先进先出)顺序存储元素的模式。

时间关系,后续章节学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值