Actor模型基于独立的小型独立进程的前提,并且只能通过消息传递来更新状态。 参与者将状态保存在自己的内部,但是异步消息传递意味着无法保证可以向调用组件提供状态的稳定视图。 对于像银行这样的交易系统,其中的帐户存款和取款必须是原子的,这与Actor模型非常不适合,因此,如果您的Akka应用程序需要实现共享状态模型并提供一致,稳定的状态视图,调用组件软件交易内存(STM)提供了答案。
STM提供了一种并发控制机制来管理对共享内存的访问。 STM利用两个概念- 乐观和事务来管理共享并发控制。
- 乐观意味着我们假设没有错误,可以并行运行多个原子块。 完成后,我们将检查是否有任何问题。 如果没有发现问题,我们将更新原子块中的状态变量。 如果发现问题,则回退并重试。 乐观并发通常提供比其他任何替代方法更好的可伸缩性选项。
- 其次,STM是在类似的数据库事务处理行上建模的。 对于STM,Java堆是具有begin / commit和rollback构造的事务数据集。 由于对象将状态保存在内存中,因此事务仅实现以下特征–原子性,一致性和隔离性。
为了将在单独线程上运行的多个事务作为一个原子块进行管理,使用了CommitBarrier的概念。
CommitBarrier是一种同步辅助工具,它被多个线程中的所有事务用作单个公共屏障点。 一旦达到障碍,所有事务都会自动提交。 它基于Java的CountDownLatch 。
Akka事务处理程序基于CommitBarrier ,其中,每个参与人员(成员)的原子块都被视为一个大的单个单元。 每个参与者都将阻止,直到参与交易的每个人都完成为止。 这意味着,即使CommitBarrier成员可能分散在多个线程中,但作为CommitBarrier成员的一部分原子块执行的所有动作似乎都将作为单个原子动作发生。 如果任何原子块引发异常或发生冲突,则所有CommitBarrier成员都会回滚。
Akka提供了一种跨角色协调事务的结构,称为ordinated.coordinated ,用于根据事务开始的位置来定义事务边界,而coordinated.coordinate()方法用于添加将参与该事务的所有成员。相同的交易环境。
两个帐户之间的汇款
让我们来看一个例子,看看参与者如何参与交易。 我们将使用在两个银行帐户之间转移资金的经典示例。 我们有一个AccountActor,用于保存帐户余额和帐号信息。 它有两个操作-贷记(向帐户添加资金)和借记(从帐户中取出资金)。 此外,我们还有TransferActor对象,该对象将保存两个AccountActor对象,然后在帐户对象上调用借方和贷方操作。
为确保帐户中的汇款同步进行,我们需要执行以下操作:
- 在帐户对象中,需要参与交易的状态变量应为交易引用类型。
- 帐户对象中的贷方和借方操作必须是原子的。
- 在转移对象中,需要定义交易边界,并且帐户对象需要参与相同的交易上下文。
- 另外,我们在TransferActor和BankActor中定义了主管策略来处理交易异常:
文章的部分内容摘自《 Akka Essentials 》一书的摘录。 有关示例的更多详细信息,请参阅本书。
参考:来自ACG Essentials博客的JCG合作伙伴 Munish K Gupta的软件事务存储(STM) 。
翻译自: https://www.javacodegeeks.com/2013/01/software-transactional-memory-stm.html