JDK-反应流(响应式流)

归档

使用示例

  • https://github.com/zengxf/small-frame-demo/blob/master/multi-thread/reactive-test/reactor-demo/src/main/java/cn/zxf/reactor_demo/jdk/PubSubTest.java

JDK 版本

openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-2724)
OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)

原理

关键类

  • java.util.concurrent.SubmissionPublisher
// 提交式-发布者
public class SubmissionPublisher<T> implements Publisher<T>, AutoCloseable {
    BufferedSubscription<T> clients;    // 客户端(BufferedSubscriptions)链表
    final ReentrantLock lock;           // 锁定以排除多个源
    volatile boolean closed;            // 运行状态,仅在锁内更新
    boolean subscribed; // 在第一次调用订阅时设置 true,以初始化可能的拥有者
    Thread owner;       // 第一个要订阅的调用者线程,如果线程发生更改则为 null
    volatile Throwable closedException; // closeExceptionally 中的异常
    final Executor executor;            // 用于构造 BufferedSubscriptions 的参数
    final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
    final int maxBufferCapacity;

    // 调用入口 ref: sign_demo_001
    public SubmissionPublisher() {
        this(ASYNC_POOL, Flow.defaultBufferSize(), null);   // ref: sign_cm_002
    }

    // sign_cm_002
    public SubmissionPublisher(
        Executor executor, int maxBufferCapacity,
        BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler
    ) {
        ... // 参数校验
        this.lock = new ReentrantLock();
        this.executor = executor;   // def: ForkJoinPool
        this.onNextHandler = handler;
        this.maxBufferCapacity = roundCapacity(maxBufferCapacity);  // def: 256
    }
}

订阅

  • java.util.concurrent.SubmissionPublisher
    // 订阅(添加订阅者)。调用入口 ref: sign_demo_010
    public void subscribe(Subscriber<? super T> subscriber) {
        if (subscriber == null) throw new NullPointerException();
        ReentrantLock lock = this.lock;
        int max = maxBufferCapacity;
        // INITIAL_CAPACITY = 32, 默认情况下计算完数组长度为 32
        Object[] array = new Object[max < INITIAL_CAPACITY ? max : INITIAL_CAPACITY]; 
        // 初始化订阅关系,ref: sign_c_110 | sign_cm_110
        BufferedSubscription<T> subscription = new BufferedSubscription<T>(
            subscriber, executor, onNextHandler, array, max
        );
        lock.lock();
        try {
            if (!subscribed) {
                subscribed = true;
                owner = Thread.currentThread();
            }
            for (BufferedSubscription<T> b = clients, pred = null;;) {
                if (b == null) {    // 还没有初始化链
                    Throwable ex;
                    subscription.onSubscribe();
                    if ((ex = closedException) != null)
                        subscription.onError(ex);   // 有异常
                    else if (closed)
                        subscription.onComplete();  // 已关闭
                    else if (pred == null)
                        clients = subscription;     // 初始化链
                    else
                        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;       // 方便遍历链
            }
        } finally {
            lock.unlock();
        }
    }
  • java.util.concurrent.SubmissionPublisher.BufferedSubscription
    // sign_c_110 订阅关系
    static final class BufferedSubscription<T> implements Subscription, ForkJoinPool.ManagedBlocker {
        long timeout;                      // Long.MAX_VALUE if untimed wait
        int head;                          // next position to take
        int tail;                          // next position to put
        final int maxCapacity;             // max buffer size
        volatile int ctl;                  // atomic run state flags
        Object[] array;                    // buffer
        final Subscriber<? super T> subscriber;
        final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
        Executor executor;                 // null on error

        BufferedSubscription<T> next;      // 组装链 

        // sign_cm_110
        BufferedSubscription(
            Subscriber<? super T> subscriber,   // 自定义的订阅者
            Executor executor,      // ForkJoinPool
            BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler, // null
            Object[] array,         // len: 32
            int maxBufferCapacity   // 256
        ) {
            this.subscriber = subscriber;
            this.executor = executor;
            this.onNextHandler = onNextHandler;
            this.array = array;
            this.maxCapacity = maxBufferCapacity;
        }
    }

提交数据

  • java.util.concurrent.SubmissionPublisher
    // 提交数据。调用入口 ref: sign_demo_020
    public int submit(T item) {
        return doOffer(item, Long.MAX_VALUE, null); // ref: sign_m_210
    }

    // sign_m_210
    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;
        ReentrantLock lock = this.lock;
        lock.lock();
        try {
            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 {
                    next = b.next;
                    int stat = b.offer(item, unowned);  // 依次发给订阅者句柄,ref: sign_m_220
                    ...
                } while ((b = next) != null);   // 遍历链

                ...
            }
        } finally {
            lock.unlock();
        }
        ...
    }
  • java.util.concurrent.SubmissionPublisher.BufferedSubscription
        // sign_m_220 添加到队列
        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 (扩容)
                    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);  // 尝试启动,ref: sign_m_221
        }

        /**
         * sign_m_221 尝试在添加后启动消费者任务
         */
        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(); // 尝试启动,ref: sign_m_222
            ...
            return stat;
        }

        // sign_m_222 尝试启动消费者任务
        final void tryStart() {
            try {
                Executor e;
                ConsumerTask<T> task = new ConsumerTask<T>(this);   // ref: sign_c_230
                if ((e = executor) != null)     // skip if disabled on error
                    e.execute(task);            // 执行体,ref: sign_c_230
            } ... // catch
        }

        // sign_m_225 消费
        final void consume() {
            Subscriber<? super T> s;
            if ((s = subscriber) != null) {          // hoist checks
                subscribeOnOpen(s); // 没开启,则开启并回调 Subscriber #onSubscribe() 方法,ref: sign_demo_110
                long d = demand;
                for (int h = head, t = tail;;) {
                    int c, taken; boolean empty;
                    if (((c = ctl) & ERROR) != 0) {
                        closeOnError(s, null);      // 有异常,回调 Subscriber #onError() 方法,ref: sign_demo_130
                        break;
                    }
                    else if ((taken = takeItems(s, d, h)) > 0) {    // 获取队列元素并处理,ref: sign_m_226
                        head = h += taken;
                        d = subtractDemand(taken);
                    }
                    ...
                    else if (t == (t = tail)) {      // stability check
                        if ((empty = (t == h)) && (c & COMPLETE) != 0) {
                            closeOnComplete(s);      // 已完成,回调 Subscriber #onComplete() 方法,ref: sign_demo_140
                            break;
                        }
                        ...
                    }
                }
            }
        }

        // sign_m_226 获取队列元素并处理
        final int takeItems(Subscriber<? super T> s, long d, int h) {
            Object[] a;
            int k = 0, cap;
            if ((a = array) != null && (cap = a.length) > 0) {
                int m = cap - 1, b = (m >>> 3) + 1;
                int n = (d < (long)b) ? (int)d : b;
                for (; k < n; ++h, ++k) {
                    Object x = QA.getAndSet(a, h & m, null); // 获取元素
                    ...
                    else if (!consumeNext(s, x)) // 通知订阅者,回调 Subscriber #onNext() 方法,ref: sign_demo_120
                        break;
                }
            }
            return k;
        }
  • java.util.concurrent.SubmissionPublisher.ConsumerTask
    // sign_c_230 消费任务(通知订阅者)
    static final class ConsumerTask<T> extends ForkJoinTask<Void>
        implements Runnable, CompletableFuture.AsynchronousCompletionTask 
    {
        final BufferedSubscription<T> consumer;
        ConsumerTask(BufferedSubscription<T> consumer) {
            this.consumer = consumer;
        }
        ... // 其他方法
        // sign_c_230 执行体
        public final void run() { consumer.consume(); } // 消费,ref: sign_m_225
    }

关闭

  • 简单,略

背压

  • 看代码或调试时,没发现 publisher 暂停的代码,可用 JConsole 查看线程栈
...
java.base@17/jdk.internal.misc.Unsafe.park(Native Method)
... .locks.LockSupport.park(LockSupport.java:211)
... .SubmissionPublisher$BufferedSubscription.block(SubmissionPublisher.java:1495) // ref: sign_m_321
... .ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3463)
... .ForkJoinPool.managedBlock(ForkJoinPool.java:3434)
... .SubmissionPublisher$BufferedSubscription.awaitSpace(SubmissionPublisher.java:1462) // ref: sign_m_320
...
  • java.util.concurrent.SubmissionPublisher
    // 提交数据。调用入口 ref: sign_demo_020
    private int doOffer(T item, long nanos, BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
        int lag = 0;
        ...
        try {
            Thread t = Thread.currentThread(), o;
            if ((unowned = ((o = owner) != t)) && o != null)
                ...
                if (retries != null || cleanMe)
                    lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);   // 背压处理,ref: sign_m_310
        } ... // finally
        ...
    }

    // sign_m_310 背压处理
    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);    // 等待,ref: sign_m_320
            ...
        }
        ...
        return lag;
    }
  • java.util.concurrent.SubmissionPublisher.BufferedSubscription
    static final class BufferedSubscription<T> implements Subscription, ForkJoinPool.ManagedBlocker {
        // sign_m_320 帮助或阻止直到超时、关闭或空间可用
        final void awaitSpace(long nanos) {
            if (!isReleasable()) {
                ForkJoinPool.helpAsyncBlocker(executor, this);
                if (!isReleasable()) {
                    timeout = nanos;
                    try {
                        ForkJoinPool.managedBlock(this);    // 最终会调用 block() 进行阻塞,ref: sign_m_321
                    } ... // catch
                }
            }
        }

        // sign_m_321 阻塞实现 (实现 ManagedBlocker 方法)
        @Override
        public final boolean block() {
            ...
            while (!isReleasable()) {
                ...
                else if (waiter == null)
                    waiter = Thread.currentThread();    // 记录当前线程
                ...
                else
                    LockSupport.park(this); // 阻塞
            }
            ...
        }

        // 在订阅者获取元素时,进行通知,继 sign_m_226
        final int takeItems(Subscriber<? super T> s, long d, int h) {
            ...
                    if (waiting != 0)
                        signalWaiter(); // 通知发布者,ref: sign_m_325
            ...
        }

        // sign_m_325 通知发布者
        final void signalWaiter() {
            Thread w;
            waiting = 0;
            if ((w = waiter) != null)
                LockSupport.unpark(w);  // 唤醒发布者线程
        }
    }
内容概要:本文详细介绍了如何利用Simulink进行自动代码生成,在STM32平台上实现带57次谐波抑制功能的霍尔场定向控制(FOC)。首先,文章讲解了所需的软件环境准备,包括MATLAB/Simulink及其硬件支持包的安装。接着,阐述了构建永磁同步电机(PMSM)霍尔FOC控制模型的具体步骤,涵盖电机模型、坐标变换模块(如Clark和Park变换)、PI调节器、SVPWM模块以及用于抑制特定谐波的陷波器的设计。随后,描述了硬件目标配置、代码生成过程中的注意事项,以及生成后的C代码结构。此外,还讨论了霍尔传感器的位置估算、谐波补偿器的实现细节、ADC配置技巧、PWM死区时间和换相逻辑的优化。最后,分享了一些实用的工程集成经验,并推荐了几篇有助于深入了解相关技术和优化控制效果的研究论文。 适合人群:从事电机控制系统开发的技术人员,尤其是那些希望掌握基于Simulink的自动代码生成技术,以提高开发效率和控制精度的专业人士。 使用场景及目标:适用于需要精确控制永磁同步电机的应用场合,特别是在面对高次谐波干扰导致的电波形失真问题时。通过采用文中提供的解决方案,可以显著改善系统的稳定性和性能,降低噪声水平,提升用户体验。 其他说明:文中不仅提供了详细的理论解释和技术指导,还包括了许多实践经验教训,如霍尔传感器处理、谐波抑制策略的选择、代码生成配置等方面的实际案例。这对于初学者来说是非常宝贵的参考资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值