reactor Publisher中使用delayElement时如何使用主线程

发布于 2025-01-14 22:28:03 字数 1132 浏览 4 评论 0原文

在reactor Publisher中使用delayElement时如何使用主线程。

Mono.just("one")
    .delayElement(Duration.ofSeconds(3))
    .subscribe(System.out::println);

如果我运行此代码,它不会打印“一”,因为主线程将退出并且订阅在其他线程上完成。

当我使用delayElement时,有没有办法使用主线程来订阅这个Mono? 即等待 3 秒后发布“one”,并直到订阅者消费它。

请注意,如果我不使用“delayElement”,我可能会阻塞主线程,直到它在屏幕上打印“one”。

Mono.just("one")
    .subscribe(System.out::println);

我知道我可以通过使用 wait 和 notification (或类似的替代方法)来实现类似的输出,但我想要的是,在调用 delayElement 后使用主线程来订阅元素。

Mono 使用的类是从 reactor.core.publisher.Mono 导入的

考虑下面的示例,其中我将使用相同的线程来延迟操作自己的实现。

Mono.just("one")
    .doOnNext(a -> this.myDelayOperation(Duration.ofSeconds(1)))
    .subscribe(System.out::println);

其中 myDelayOperation(...) 是

private void myDelayOperation(Duration duration) {
    try {
        Thread.sleep(duration.toMillis());
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

How to use main thread when delayElement is used in reactor Publisher.

Mono.just("one")
    .delayElement(Duration.ofSeconds(3))
    .subscribe(System.out::println);

If I run this code, it will not print "one", because main thread will exit and subscription is done on other thread.

Is there a way to use main thread for subscription of this Mono when I use delayElement?
i.e. wait until "one" is published down the line after 3 seconds, and until subscriber consume it.

Please mind that if I would not have used "delayElement", I could have blocked main thread until it print "one" on screen.

Mono.just("one")
    .subscribe(System.out::println);

I am aware that I can achieve similar output by using wait and notify (or similar alternative), but what I want is, to use main thread for subscribing element after delayElement is called.

Mono class used is imported from reactor.core.publisher.Mono

Consider below example, in which I will use same thread for delay operation of my own implementation.

Mono.just("one")
    .doOnNext(a -> this.myDelayOperation(Duration.ofSeconds(1)))
    .subscribe(System.out::println);

where myDelayOperation(...) is

private void myDelayOperation(Duration duration) {
    try {
        Thread.sleep(duration.toMillis());
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半﹌身腐败 2025-01-21 22:28:03

免责声明:所有这些解决方案都不建议用于生产。仅用于测试和学习目的。

调试:在代码中添加日志

    public static void main(String[] args) {
            System.out.println("Method Start Thread : "+Thread.currentThread().getName());
            Mono.just("one")
                    .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                    .delayElement(Duration.ofSeconds(5))
                    .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                    .subscribe(val->System.out.println("Final Value: "+val+" Value Thread : "+Thread.currentThread().getName()));
            System.out.println("Method Exit Thread: "+Thread.currentThread().getName());
    }

输出:

  • 方法启动线程:main
  • 延迟 Value:one 和 Value Thread:main 之前
  • 方法退出线程:main
  • 进程已完成,退出代码为 0

说明:这里注意,在打印“延迟值之后”之前,主线程已退出。因为delayElement()不会在主线程上运行,而是在称为“并行”的不同线程上运行。在并行线程完成其操作之前,主线程已退出,因此您看不到值“one”

解决方案1:使主线程在一段时间内不退出

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.just("one")
                .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .delayElement(Duration.ofSeconds(5))
                .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .subscribe(val->System.out.println("Final Value: "+val+" Value Thread : "+Thread.currentThread().getName()));

        try {
            System.out.println("Sleeping Thread: "+Thread.currentThread().getName());
            Thread.sleep(10000);
            System.out.println("Wake up Thread: "+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

输出:

  • 方法启动线程:main
  • 延迟 Value:one 和 Value Thread: main 之前
  • 睡眠线程:主
  • 延迟值:one 和值线程:parallel-1 后
  • 最终值:一个值线程:parallel-1
  • 唤醒线程:main
  • 方法退出线程:main
  • 进程已完成,退出代码为 0

说明:这里请注意,“延迟值之后”是在主线程处于睡眠状态时(在退出之前)打印的。另请注意,如前所述,delayElement() 不在主线程上运行,而是在称为“parallel-1”的不同线程上运行。

解决方案:2 使用 block()

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.just("one")
                .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .delayElement(Duration.ofSeconds(5))
                .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .block();
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

输出:

  • 方法启动线程:main
  • 延迟 Value:one 和 Value Thread: main 之前
  • 延迟值:one 和值线程:parallel-1 后
  • 方法退出线程:main
  • 进程已完成,退出代码为 0

说明: 这里请注意,因为我们阻塞了主线程,所以打印了字符串“延迟值之后”。因此,在管道返回值之前,它将被阻塞。

解决方案 3:编写自定义执行器:强烈不推荐

.delayElement(Duration.ofSeconds(5), Schedulers.fromExceutor(wirteAndCallYourOwnExecutorToBlockCurrentMainThread))

解决方案 4:使用 Mono Callable 进行阻止

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.fromCallable(()->{
                    try {
                        System.out.println("Sleeping Thread: "+Thread.currentThread().getName());
                        Thread.sleep(10000);
                        System.out.println("Wake up Thread: "+Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    return "one";
                })
                .doOnNext(next->System.out.println("Received Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .subscribe();
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

输出:

  • 方法启动线程:main
  • 睡眠线程:主
  • 唤醒线程:main
  • 收到的值:one 和值线程:main
  • 方法退出线程:main
  • 进程已完成,退出代码为 0

>建议:如果是产品,最好使用异步而不阻塞。我不知道你的完整用例。因此,在最坏的情况下,如果需要,请使用方法 4,风险自负。

Disclaimer: All these solutions are not recommended for production. Only for testing and learning purpose.

Debugging: Added Logs on your code

    public static void main(String[] args) {
            System.out.println("Method Start Thread : "+Thread.currentThread().getName());
            Mono.just("one")
                    .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                    .delayElement(Duration.ofSeconds(5))
                    .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                    .subscribe(val->System.out.println("Final Value: "+val+" Value Thread : "+Thread.currentThread().getName()));
            System.out.println("Method Exit Thread: "+Thread.currentThread().getName());
    }

Output:

  • Method Start Thread : main
  • Before delay Value:one and Value Thread:main
  • Method Exit Thread: main
  • Process finished with exit code 0

Explanation: Here notice, before printing "After delay value" main-thread got exit. Because delayElement() will not run on main thread and it will run on different thread called "parallel". Before parallel thread completes its operation, main thread got exited, so you are not seeing value "one"

Solution 1: Making main thread not to exit for some time

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.just("one")
                .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .delayElement(Duration.ofSeconds(5))
                .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .subscribe(val->System.out.println("Final Value: "+val+" Value Thread : "+Thread.currentThread().getName()));

        try {
            System.out.println("Sleeping Thread: "+Thread.currentThread().getName());
            Thread.sleep(10000);
            System.out.println("Wake up Thread: "+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

Output:

  • Method Start Thread : main
  • Before delay Value:one and Value Thread: main
  • Sleeping Thread: main
  • After delay Value:one and Value Thread: parallel-1
  • Final Value: one Value Thread : parallel-1
  • Wake up Thread: main
  • Method Exit Thread: main
  • Process finished with exit code 0

Explanation: Here notice,"After delay value" was printed while main thread was sleep (before its exit). Also note as said earlier delayElement() does not ran on main thread and it ran on different thread called "parallel-1".

Solution :2 Using block()

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.just("one")
                .doOnNext(next->System.out.println("Before delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .delayElement(Duration.ofSeconds(5))
                .doOnNext(next->System.out.println("After delay Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .block();
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

Output:

  • Method Start Thread : main
  • Before delay Value:one and Value Thread: main
  • After delay Value:one and Value Thread: parallel-1
  • Method Exit Thread: main
  • Process finished with exit code 0

Explanation: Here notice, string "After delay value" was printed because we blocked main thread. So until pipeline returns a value it will be blocked.

Solution 3: Writing custom executor: Highly not recommended

.delayElement(Duration.ofSeconds(5), Schedulers.fromExceutor(wirteAndCallYourOwnExecutorToBlockCurrentMainThread))

Solution 4: Block using Mono Callable

public static void main(String[] args) {
        System.out.println("Method Start Thread : "+Thread.currentThread().getName());
        Mono.fromCallable(()->{
                    try {
                        System.out.println("Sleeping Thread: "+Thread.currentThread().getName());
                        Thread.sleep(10000);
                        System.out.println("Wake up Thread: "+Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    return "one";
                })
                .doOnNext(next->System.out.println("Received Value:"+next+" and Value Thread: "+Thread.currentThread().getName()))
                .subscribe();
        System.out.println("Method Exit Thread: "+Thread.currentThread().getName());

Output:

  • Method Start Thread : main
  • Sleeping Thread: main
  • Wake up Thread: main
  • Received Value:one and Value Thread: main
  • Method Exit Thread: main
  • Process finished with exit code 0

> Recommendation: If it was prod, better go with async without blocking. I don't know your complete use case. So, in worst case if required use approach 4 with your own risk.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文