Java Akka及其错误内核

Java Akka及其错误内核,java,akka,immutability,actor,Java,Akka,Immutability,Actor,我正在阅读Akka(Javalib)文档,需要澄清其中的一些问题 参与者不应该在某些外部实体上阻塞(即,在占用线程时被动等待)……阻塞操作应该是 在一些特殊的情况下,发送信息给演员,演员将采取行动 那么在Akka/Java中这个代码示例是什么样子的呢?如果一个Actor不是放置必须阻塞的代码的合适位置,那么什么满足“一些特殊情况线程”的定义呢 不要在参与者之间传递可变对象。为了确保这一点,我们更喜欢不可变的消息 我熟悉如何创建不可变类(没有公共setter,没有公共字段,使类成为final等)。

我正在阅读Akka(Javalib)文档,需要澄清其中的一些问题

参与者不应该在某些外部实体上阻塞(即,在占用线程时被动等待)……阻塞操作应该是 在一些特殊的情况下,发送信息给演员,演员将采取行动

那么在Akka/Java中这个代码示例是什么样子的呢?如果一个
Actor
不是放置必须阻塞的代码的合适位置,那么什么满足“一些特殊情况线程”的定义呢

不要在参与者之间传递可变对象。为了确保这一点,我们更喜欢不可变的消息

我熟悉如何创建不可变类(没有公共setter,没有公共字段,使类成为final等)。但是阿克卡对“不可变类”有自己的定义吗?如果有,它是什么

顶级参与者是错误内核的最内部部分


我甚至不知道这是什么意思!我理解他们所说的“顶级”演员(演员/经理/主管层级中的最高级别)的含义,但“错误内核”是什么,它与演员有什么关系?

我只能回答第一个问题(将来,请在帖子中只放一个问题)。 例如,考虑一个数据库连接,它本质上是阻塞的。为了允许参与者连接到数据库,程序员应该创建一个带有数据库请求队列的专用线程(或线程池)。请求包含一条数据库语句和对要接收结果的参与者的引用。专用线程读取循环中的请求,访问数据库,将结果发送给引用的参与者等。请求队列被阻塞-当没有请求时,连接线程在
队列中被阻塞。take()
操作

因此,对数据库的访问分为两个角色——一个向队列发出请求,另一个处理结果

更新:Java代码草图(我不擅长Scala)

类请求{
字符串查询;
ActorRef处理程序;
}
类DatabaseConnector实现可运行{
LinkedBlockingQueue=新建LinkedBlockingQueue();
螺纹t=新螺纹(此);
{t.start();}
公共无效发送请求(请求r){
队列。put(r);
}
公开募捐{
对于(;;){
请求r=queue.take();
ResultSet res=doBlockingCallToJdbc(r.query);
r、 handler.sendOneWay(res);
}
}

以下是第二个问题的答案。请点击:

如果一个参与者携带非常重要的数据(即其状态不应为 如果可以避免的话,这个演员应该找出任何可能的线索 它监督和处理儿童的危险子任务 这些儿童视情况而定。这取决于 请求时,最好为每个请求创建一个新的子级 简化收集回复的状态管理。这是已知的 作为来自Erlang的“错误内核模式”

因此,你所说的这句话意味着,这些参与者是你监管层级中的错误的“最后一道防线”,因此他们应该是强壮有力的人(突击队员)而不是一些软弱的工人。你的突击队员越少,管理他们就越容易,避免高层混乱。确切地说,突击队员的数量应该接近你拥有的商业协议的数量(转向超级英雄——比如说一个是铁人,一个是绿巨人等等)

本文档还很好地解释了如何管理阻塞操作

说到这里

如果一个参与者不是放置代码的合适位置,那么什么才能满足“某些特殊情况线程”的定义

Actor显然不这样做,因为Akka只保证顺序性,但您的消息可以在任何线程上处理(它只是从池中拾取一个空闲线程),即使对于单个Actor也是如此。不建议在那里执行阻止操作(至少在与普通线程相同的线程池中)因为它们可能会导致性能问题甚至死锁。例如,请参阅Spray的说明(它基于Akka):

您可能会想到AKKA只需要与异步API进行交互。您可以考虑将同步转换为异步。只需将响应从数据库发送给参与者。Scala示例:

 receive = { //this is receiving method onReceive
     case query: Query => //query is message safely casted to Query 
          Future { //this construction marks a peace of code (handler) which will be passed to the future 
            //this code will be executed in separate thread:
            doBlockingCallToJdbc(query)
          } pipeTo sender //means do `sender ! futureResult` after future's completion
     }
 }

其他方法在同一个文档()中进行了描述()

谢谢@Alexei K.(+1)-这是一个很好的用例,但我仍在努力通过树看到森林“。你有没有可能用一些伪代码更新你的答案,显示
DatabaseRequest
对象、队列和其他任何东西来完成它?不要担心JDBC之类的东西,我认为
doBlockingDatabaseCall()
方法足以帮助我100%理解这一点。再次感谢!”意味着所有字段都是
final
,没有外部或内部的修改。只有这样,对象才能安全地在多个线程之间共享,而不会(代价高昂)synchronization.Futures可能不是最好的解决方案。请参阅akka,了解处理阻塞的所有方法。@Oleksndr.Bezhan该链接已包含在我的答案中,Sasha。如果您暗示发件人引用或故障报告问题,则可通过pipeTo解决。简单的请求响应不需要状态,因此此处不存在异步变异。池管理可以通过直接管理池或从akka config导入池来完成。我提到的第一个链接(部分引用)和您重复的第一个链接(为什么?)指向所有可能的解决方案,包括未来解决方案。
 receive = { //this is receiving method onReceive
     case query: Query => //query is message safely casted to Query 
          Future { //this construction marks a peace of code (handler) which will be passed to the future 
            //this code will be executed in separate thread:
            doBlockingCallToJdbc(query)
          } pipeTo sender //means do `sender ! futureResult` after future's completion
     }
 }