10.2Thread Safety
0.Thread safety
1.Strategy 1: Confinement 限制共享
2.Strategy 2: Immutability 共享不变量
3.Strategy 3: Using Threadsafe Data Types 用线程安全数据类型
4.Strategy 4: Locks and Synchronization 线程锁
5.How to Make a Safety Argument 怎么说明安全
0.线程安全
线程竞争导致Post condition可能违反。
线程安全指ADT或方法在多线程中要执行正确。(不违反spec和RI)
Itreator是线程不安全的,remove()也是不安全的,在Java doc有说明
4种保证threadsafety的方法:
1.限制共享数据(不和其他线程共享数据)
2.共享不可变数据(保持数据是immutable的)
3.共享线程安全的可变数据(保证数据的操作是线程安全的)
4.同步机制:通过锁的机制共享线程不安全的可变数据,变并行为串行(线程锁)
1.Confinement 限制数据共享
方法:将可变数据限制在单一线程内部,避免竞争,不允许任何线程直接读写该数据
核心思想:线程之间不共享 mutable 数据类型
!!:之前为了优化,而设计的Singleton 设计模式会导致创建对象时发生竞争,可能创建两次对象,导致 线程不安全
避免使用全局变量,如果可以也别使用静态变量(所有调用此静态变量的方法,如果被多个线程调用多次,是会发生竞争的)
如果一个 ADT 的 rep 中包含mutable 的属性且多线程之间对其进行 mutator 操作,那么就很难使用 confinement 策略来确保该 ADT是线程安全的
2.Immutability 保持数据不变
使用不可变数据类型和不可变引用,通常避免多线程之间的竞争情况(数据只读)
PS:beneficent mutation为特殊情况,这时可能竞争
为了保证线程安全,我们强定义immutability:
--不准有mutator ---没有setter
--所有属性都是private and final
--No rep exposure
--什么情况也不允许mutation(包括beneficent mutation,保证子类安全,不允许override)
对于数据的引用采用防御性拷贝
3.Using Threadsafe DataTypes 用线程安全数据类型
如果必须要用 mutable 的数据类型在多线程之间共享数据,要使用线程安全的数据类型。(Threadsafe 的数据类型,JAVA文档中明确指出,通常保证线程安全会影响性能)
集合类(Set,Map,List)都是不安全的,JAVA API 提供decorator模式保证这些集合类线程安全(synchronized+集合类的类型)
最好不保留别名,不把hashMap共享给其他线程
PS!!!:即使线程安全的集合类依然可能线程不安全(1.遍历或iterator;2.使用多个操作)
如左图,当第一行语句结束后可能其他线程调用remove(),依然不安全
PS:所有数组都是线程不安全的
总结一下:1.最好不共享数据 2.共享不变的数据 3.共享线程安全的数据
4.How to make a safety argument 用线程安全数据类型
Spec:对线程安全说明
Test:测试线程安全的状况
Rep:写好AF,RI,checkRep
Thread Safety Arguments:显式说明保证线程安全的决策,采取什么的方法保证安全