《代码整洁之道》—第13章13.3节并发防御原则

本节书摘来自异步社区《代码整洁之道》一书中的第13章13.3节并发防御原则,作者【美】Robert C. Martin,更多章节内容可以访问云栖社区“异步社区”公众号查看。

13.3 并发防御原则
下面给出一系列防御并发代码问题的原则和技巧。

13.3.1  单一权责原则
单一权责原则(SRP)[5]认为,方法/类/组件应当只有一个修改的理由。并发设计自身足够复杂到成为修改的理由,所以也该从其他代码中分离出来。不幸的是,并发实现细节常常直接嵌入到其他生产代码中。下面是要考虑的一些问题:

并发相关代码有自己的开发、修改和调优生命周期;
开发相关代码有自己要对付的挑战,和非并发相关代码不同,而且往往更为困难;
即便没有周边应用程序增加的负担,写得不好的并发代码可能的出错方式数量也已经足具挑战性。
建议:分离并发相关代码与其他代码[6]。

13.3.2 推论:限制数据作用域
如我们所见,两个线程修改共享对象的同一字段时,可能互相干扰,导致未预期的行为。解决方案之一是采用synchronized关键字在代码中保护一块使用共享对象的临界区(critical section)。限制临界区的数量很重要。更新共享数据的地方越多,就越可能:

你会忘记保护一个或多个临界区——破坏了修改共享数据的代码;
得多花力气保证一切都受到有效防护(破坏了DRY原则[7]);
很难找到错误源,也很难判断错误源。
建议:谨记数据封装;严格限制对可能被共享的数据的访问。

13.3.3 推论:使用数据复本
避免共享数据的好方法之一就是一开始就避免共享数据。在某些情形下,有可能复制对象并以只读方式对待。在另外的情况下,有可能复制对象,从多个线程收集所有复本的结果,并在单个线程中合并这些结果。

如果有避免共享数据的简易手段,结果代码就会大大减少导致错误的可能。你可能会关心创建额外对象的成本。值得试验一下看看那是否真是个问题。然而,假使使用对象复本能避免代码同步执行,则因避免了锁定而省下的价值有可能补偿得上额外的创建成本和垃圾收集开销。

13.3.4 推论:线程应尽可能地独立
让每个线程在自己的世界中存在,不与其他线程共享数据。每个线程处理一个客户端请求,从不共享的源头接纳所有请求数据,存储为本地变量。这样一来,每个线程都像是世界中的唯一线程,没有同步需要。

例如,HttpServlet的子类接收所有以参数形式传递给doGet和doPost方法的信息。每个Servlet都像拥有独立虚拟机一般运行。只要Servlet中的代码只使用本地变量,Servlet就不会导致同步问题。当然,多数使用Servlet的应用程序最终都还是会用到类似数据库连接之类的共享资源。

建议:尝试将数据分解到可被独立线程(可能在不同处理器上)操作的独立子集。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值