知识卡片

外部状态划分过粗会引发共享对象的线程安全问题

普通读书笔记卡 · 1860.a.1.b

内容

[[享元模式的定义、内外部状态与四个角色]]的共享对象天生是多线程资源,若外部状态划分 过粗(如只用”科目”而非”科目+地点”),池变小但更多本该独立的实体被迫共享同一实例—— 多线程各自设置id和location时会互相覆盖,出现”张三编号配李四地址”的脏数据。发散:共享 粒度是安全性与内存的权衡——粒度越粗池越小但冲突越高,经验是”享元对象数量尽量多,多到 足够满足业务需要”,用更细粒度换更小冲突面。

参考来源

- 位置:《设计模式之禅(第2版)》第28章《享元模式》(源文件:_epub-src/text/part0129.html) - 结论依据:原文把外部状态简化为只按"考试科目"分组、用多线程场景演示两个线程同时修改同一个共享对象的id和location字段导致数据错乱("编号:LiSi,考试地址:ZhangSan,线程不安全了!"),并总结"设置的享元对象数量太少,导致每个线程都到对象池中获得对象,然后都去修改其属性……在使用享元模式时,对象池中的享元对象尽量多,多到足够满足业务为止"。 - 原始内容:为什么要以考试科目+考试地点作为外部状态呢?为什么不能以考试科目或者考试地点作为外部状态呢?这样池中的对象会更少!……看看,线程不安全了吧,这是正常的,设置的享元对象数量太少……在使用享元模式时,对象池中的享元对象尽量多,多到足够满足业务为止。