java Flow 执行流程

22 篇文章 1 订阅


前言

使用上一篇文章的例子来调试一下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、订阅者在获取到消息后,唤醒发布者线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本课程是《Flowable流程入门课程》的后续高级课程。在学习本课程前,应先学习入门课程,以掌握相关基础知识。高级课程着重讲解Flowable工作流的高级概念、复杂理论和实战应用。课程内容包括流程管理思想、技术与标准、工作流的控制模式和资源模式;Flowable数据库表及变量;与Spring、Spring Boot的集成;BPMN 2.0主要类图;Flowable高级服务如JAVA服务任务、脚本任务、Web Service任务、外部工作者任务、多实例任务、补偿处理程序、子流程和调用活动等;Flowable事件侦听器、执行侦听器和任务侦听器;Flowable历史和REST API;Flowable事务、并发性、身份管理及LDAP集成;Flowable高级主题如流程实例迁移、异步执行器的设计与配置、用于高并发的UUID ID生成器、多租户、高级流程引擎配置、执行自定义SQL和实验性流程调试器等;Flowable Eclipse设计器特性及定制;Flowable 事件注册;Flowable相关标准和规范如ISO8601标准和cron等。本课程对Flowable官方文档进行了彻底梳理和融汇贯通,并结合实践,形象生动、系统全面、简单易懂地呈现给大家,让大家从开源软件文档冗长耗时、英文晦涩难懂、概念理解困难、知识点分散等困境中解脱出来,从而能快速地将Flowable具有的高级特性应用到项目的高级需求和复杂实践中去。课程特色:案例和代码驱动、基础概念与经典实战相结合、知识环节融会贯通、关联知识平滑拓展、概念和原理展示形象生动。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_lrs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值