前言
使用上一篇文章的例子来调试一下Flow的执行流程。
一、流程
1、发布者与消费者建立关系
publisher.subscribe(processor);
(1)subscribe()
public void subscribe(Subscriber<? super T> subscriber) {
if (subscriber == null) throw new NullPointerException();
int max = maxBufferCapacity; // allocate initial array
Object[] array = new Object[max < INITIAL_CAPACITY ?
max : INITIAL_CAPACITY];
BufferedSubscription<T> subscription =
new BufferedSubscription<T>(subscriber, executor, onNextHandler,
array, max);
synchronized (this) {
if (!subscribed) {
//表示有订阅者了
subscribed = true;
//首次调用订阅的线程
owner = Thread.currentThread();
}
//遍历订阅者 clients
for (BufferedSubscription<T> b = clients, pred = null;;) {
//到了链表的末尾
if (b == null) {
Throwable ex;
//调用最新订阅者的onSubscribe()
subscription.onSubscribe();
if ((ex = closedException) != null)
//生产者异常,通知订阅者
subscription.onError(ex);
else if (closed)
//生产者关闭,通知订阅者
subscription.onComplete();
else if (pred == null)
//链表为空时
clients = subscription;
else
//链表不为空,设置最新订阅者为next
pred.next = subscription;
break;
}
//获取链表的下一个
BufferedSubscription<T> next = b.next;
if (b.isClosed()) { // remove
//订阅者关闭了,移除
b.next = null; // detach
//链表向后移动
if (pred == null)
clients = next;
else
pred.next = next;
}
//重复订阅了
else if (subscriber.equals(b.subscriber)) {
b.onError(new IllegalStateException("Duplicate subscribe"));
break;
}
else
//记录前一个节点
pred = b;
//节点后移
b = next;
}
}
}
(2)subscription.onSubscribe();
校验状态,启动订阅者消费线程
final void onSubscribe() {
startOnSignal(RUN | ACTIVE);
}
final void startOnSignal(int bits) {
if ((ctl & bits) != bits &&
(getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
tryStart();
}
final void tryStart() {
try {
Executor e;
//创建消费任务
ConsumerTask<T> task = new ConsumerTask<T>(this);
//使用 ForkJoinPool 执行任务
if ((e = executor) != null) // skip if disabled on error
e.execute(task);
} catch (RuntimeException | Error ex) {
getAndBitwiseOrCtl(ERROR | CLOSED);
throw ex;
}
}
3、ConsumerTask
这里 consume是 BufferedSubscription
public final void run() { consumer.consume(); }
4、BufferedSubscription.consume()
final void consume() {
Subscriber<? super T> s;
if ((s = subscriber) != null) { // hoist checks
//开启订阅,调用 Subscribe 的 onSubscribe() 方法
subscribeOnOpen(s);
long d = demand;
for (int h = head, t = tail;;) {
int c, taken; boolean empty;
if (((c = ctl) & ERROR) != 0) {
closeOnError(s, null);
break;
}
//获取消息
else if ((taken = takeItems(s, d, h)) > 0) {
head = h += taken;
d = subtractDemand(taken);
}
//没有获取到消息
else if ((d = demand) == 0L && (c & REQS) != 0)
weakCasCtl(c, c & ~REQS); // exhausted demand
else if (d != 0L && (c & REQS) == 0)
weakCasCtl(c, c | REQS); // new demand
else if (t == (t = tail)) { // stability check
if ((empty = (t == h)) && (c & COMPLETE) != 0) {
//发布者完成数据发布
closeOnComplete(s); // end of stream
break;
}
else if (empty || d == 0L) {
//发布者没有发布数据
int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
if (weakCasCtl(c, c & ~bit) && bit == RUN)
break; // un-keep-alive or exit
}
}
}
}
}
5、takeItems
获取消息
final int takeItems(Subscriber<? super T> s, long d, int h) {
Object[] a;
int k = 0, cap;
//从 array 中获取发布者的数据
if ((a = array) != null && (cap = a.length) > 0) {
int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
int n = (d < (long)b) ? (int)d : b;
for (; k < n; ++h, ++k) {
//获取到数据
Object x = QA.getAndSet(a, h & m, null);
if (waiting != 0)
//发布者被阻塞了,唤醒它
signalWaiter();
if (x == null)
//没有要消费的数据了
break;
else if (!consumeNext(s, x))
break;
}
}
return k;
}
6、consumeNext()
调用消费者消费数据
final boolean consumeNext(Subscriber<? super T> s, Object x) {
try {
@SuppressWarnings("unchecked") T y = (T) x;
if (s != null)
s.onNext(y);
return true;
} catch (Throwable ex) {
handleOnNext(s, ex);
return false;
}
}
这里先调用 Processor 消费数据
@Override
public void onNext(String item) {
System.out.println("Processor 接收数据: " + item);
item += " Processor 处理后的消息";
this.submit(item);
this.subscription.request(1);
}
2、发布者发布消息
publisher.submit(msg);
(1)submit()
public int submit(T item) {
return doOffer(item, Long.MAX_VALUE, null);
}
private int doOffer(T item, long nanos,
BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
if (item == null) throw new NullPointerException();
int lag = 0;
boolean complete, unowned;
synchronized (this) {
Thread t = Thread.currentThread(), o;
BufferedSubscription<T> b = clients;
if ((unowned = ((o = owner) != t)) && o != null)
owner = null; // disable bias
if (b == null)
complete = closed;
else {
complete = false;
boolean cleanMe = false;
BufferedSubscription<T> retries = null, rtail = null, next;
//do while 循环调用订阅者各自的 offer() 方法将消息放入缓存
do {
next = b.next;
int stat = b.offer(item, unowned);
if (stat == 0) { // saturated; add to retry list
b.nextRetry = null; // avoid garbage on exceptions
if (rtail == null)
retries = b;
else
rtail.nextRetry = b;
rtail = b;
}
else if (stat < 0) // closed
cleanMe = true; // remove later
else if (stat > lag)
lag = stat;
} while ((b = next) != null);
//没有将数据添加到缓存
if (retries != null || cleanMe)
lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
}
}
if (complete)
throw new IllegalStateException("Closed");
else
return lag;
}
(2)offer()
final int offer(T item, boolean unowned) {
Object[] a;
int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
int t = tail, i = t & (cap - 1), n = t + 1 - head;
if (cap > 0) {
boolean added;
if (n >= cap && cap < maxCapacity) // resize
//数组初始容量是32,满了后进行2倍扩容
added = growAndOffer(item, a, t);
else if (n >= cap || unowned) // need volatile CAS
//并发时通过 cas 加入缓存
added = QA.compareAndSet(a, i, null, item);
else { // can use release mode
//存入缓存数组
QA.setRelease(a, i, item);
added = true;
}
if (added) {
tail = t + 1;
stat = n;
}
}
//尝试开启消费者
return startOnOffer(stat);
}
(3)startOnOffer()
final int startOnOffer(int stat) {
int c; // start or keep alive if requests exist and not active
if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
//开启
tryStart();
else if ((c & CLOSED) != 0)
stat = -1;
return stat;
}
进入消费消息流程,前面已经分析过了
final void tryStart() {
try {
Executor e;
ConsumerTask<T> task = new ConsumerTask<T>(this);
if ((e = executor) != null) // skip if disabled on error
e.execute(task);
} catch (RuntimeException | Error ex) {
getAndBitwiseOrCtl(ERROR | CLOSED);
throw ex;
}
}
(4)retryOffer()
没有将消息添加到缓存,阻塞发布者线程
private int retryOffer(T item, long nanos,
BiPredicate<Subscriber<? super T>, ? super T> onDrop,
BufferedSubscription<T> retries, int lag,
boolean cleanMe) {
for (BufferedSubscription<T> r = retries; r != null;) {
BufferedSubscription<T> nextRetry = r.nextRetry;
r.nextRetry = null;
if (nanos > 0L)
//等待缓存有空间
r.awaitSpace(nanos);
int stat = r.retryOffer(item);
if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
stat = r.retryOffer(item);
if (stat == 0)
lag = (lag >= 0) ? -1 : lag - 1;
else if (stat < 0)
cleanMe = true;
else if (lag >= 0 && stat > lag)
lag = stat;
r = nextRetry;
}
if (cleanMe)
cleanAndCount();
return lag;
}
(5)awaitSpace()
final void awaitSpace(long nanos) {
//检测是否关闭、空间是否释放
if (!isReleasable()) {
ForkJoinPool.helpAsyncBlocker(executor, this);
if (!isReleasable()) {
timeout = nanos;
try {
//没有释放,阻塞订阅者
ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
timeout = INTERRUPTED;
}
if (timeout == INTERRUPTED)
Thread.currentThread().interrupt();
}
}
}
(6)managedBlock()
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
if (blocker == null) throw new NullPointerException();
ForkJoinPool p;
ForkJoinWorkerThread wt;
WorkQueue w;
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
(p = (wt = (ForkJoinWorkerThread)t).pool) != null &&
(w = wt.workQueue) != null) {
int block;
while (!blocker.isReleasable()) {
if ((block = p.tryCompensate(w)) != 0) {
try {
//再次检测空间是否释放,调用block阻塞
do {} while (!blocker.isReleasable() &&
!blocker.block());
} finally {
CTL.getAndAdd(p, (block > 0) ? RC_UNIT : 0L);
}
break;
}
}
}
else {
do {} while (!blocker.isReleasable() &&
!blocker.block());
}
}
(7)
public final boolean block() {
long nanos = timeout;
boolean timed = (nanos < Long.MAX_VALUE);
long deadline = timed ? System.nanoTime() + nanos : 0L;
while (!isReleasable()) {
if (Thread.interrupted()) {
timeout = INTERRUPTED;
if (timed)
break;
}
else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
break;
else if (waiter == null)
//等待线程
waiter = Thread.currentThread();
else if (waiting == 0)
waiting = 1;
else if (timed)
//阻塞等待
LockSupport.parkNanos(this, nanos);
else
LockSupport.park(this);
}
waiter = null;
waiting = 0;
return true;
}
二、总结
1、发布者与订阅者建立关联时,会开启订阅者线程尝试从缓存获取发布者消息,获取不到时会退出线程;
2、发布者发布消息时,会将消息放入缓存,同时会尝试开启订阅者线程进行消息消费;
3、发布者发布消息过多时,阻塞发布者线程;
4、订阅者在获取到消息后,唤醒发布者线程。