读书笔记: Java虚拟机并发编程

https://book.douban.com/people/fleure/annotation/24533312/

明智地进行选择 - 软件事务内存

<原文开始> STM 是经由 Clojure 成功实践之后才逐渐流行起来的。</原文结束> <原文开始>然而 STM 存在两个主要缺陷。其一,如果项目所使用的语言不是 Clojure,那么必须格外小心,以确保所处理的状态除了托管实体都是不可变的。其二,必须确保事务的实现代码都是幂等的且无任何副作用。 </原文结束> <原文开始> STM 更适合那些写冲突不频繁的场景。 </原文结束> ## 基于 Actor 模型的局限性 <原文开始>在那些没有强制不变性的语言中,我们必须人工保证消息都是不可变的。</原文结束> <原文开始>某些 Actor 的意外失败有可能导致其它 Actor 饿死,一个或多个 Actor 可能会一直等待某些关键的协作消息,而这些消息有可能由于本应发出该消息的 Actor 失败而永远无法抵达。因此,我们需要谨慎编码,在 Actor 中加入异常情况的处理逻辑,并将错误消息传播给那些等待响应的 Actor。</原文结束> <原文开始>当两个或多个 Actor 互相等待对方发来的消息时,所有的 Actor 都将陷入死锁。我们应该使用超时来保证程序不会由于协调环节中各别 Actor 的无法响应而导致其它 Actor 无限期的等待。</原文结束> <原文开始>只有在待解决的任务可以被拆分成多个彼此相互独立的子任务并且子任务之间只有少量交互的情况下,使用 Actor 才是合适的。但如果子任务之间需要频繁交互或者子任务们需要通过形成一个裁决集(quorum)的形式来进行协作,则使用 Actor 模型是不合适的。</原文结束> ## 保持不变式 <原文开始>一方面,我们绝不应该在构造函数中启动线程;而另一方面,我们也不愿意在对象没有完全创建好之前就启动它。 解决方案就是在 《Effective Java》一书的第一项中:“考虑使用静态工厂函数来代替构造函数”。即在一个静态工厂函数中创建对象实例,并在将实例的引用返回给调用方之前启动线程。 我们绝对不要访问一个处于无效状态中的对象。 </原文结束> 之前写代码似乎没有很注意这点:构造函数中对象自身仍是 broke 的,绝对不要泄露它的引用。