在 Actor 内创建自定义线程?

问题描述 投票:0回答:1

当我的基于 akka 的应用程序运行时,有时我会看到此错误:

[ERROR] [2024-01-02 07:30:41.524] [xxxx.dispatcher-22680] Uncaught error from thread [xxxx.dispatcher-22680]: unable to create new native thread, shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[....]
java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:719)
    ....

当远程服务不可用时会发生这种情况。

将错误日志映射到代码,我看到在 Actor 内部正在创建一个线程:

val refreshThread = new Thread() {....}
refreshThread.start()

这就是错误发生的地方。

我知道 akka actor 在一个线程上执行,该线程的调度和所有其他管理都由 akka 调度程序负责,从而使开发人员免于陷入线程相关的代码。 但这里在 actor 本身内部创建了一个线程。

akka 是如何管理这些线程的?

我想知道在 akka 上下文中创建这样的自定义线程是否是可接受的做法。

另外,处理这种情况的正确方法是什么?

scala akka
1个回答
0
投票

此类线程根本不会由 Akka 管理,就像 Actor 中的任何资源一样。

这在 Akka 中是可以接受的做法吗?几乎肯定不会:通常有更好的抽象可用。选择哪种抽象取决于您到底希望线程执行什么操作。

例如,

Thread
是一个
Runnable
:如果调用
start()
,它只会分叉为新线程。您可以从
ActorSystem
获取调度程序(线程池),并让该调度程序在其中一个线程上运行
Runnable
,而不是在新线程上:Akka Classic 和 Akka 之间的确切机制会略有不同打字。请注意,如果沿着这条路径走下去,
Thread
不应该创建新线程(因为那时我们基本上回到这里),也不应该执行长时间运行的任务。您可能会发现配置一个调度程序(例如,由
thread-pool-executor
支持的用于阻塞任务的调度程序)对于运行这样的线程很有用。请注意,在线程池上执行事物意味着它们可能要经过一段时间才能真正执行。

另一种选择(可能更理想),是将线程正在执行的操作重构为更小的工作单元,并使用 future 或 actor 等抽象来管理工作单元,但这可能是一次实质性的重构。

© www.soinside.com 2019 - 2024. All rights reserved.