《JAVA并发编程实战---读书笔记2》

来源:互联网 发布:mmd格斗动作数据下载 编辑:程序博客网 时间:2024/06/06 00:57

这里是基于书的第4章---对象的组合

1.不可变条件以及后验条件

(1)不可变条件

用于判断状态是有效还是无效的

比如,一个long类型的变量,其状态空间从Long.MIN_VALUE到Long.MAX_VALUE

并且由程序的实际意义可能要求必须取正值等。

(2)后验条件

用于判断状态转换的有效性

比如,一个递增的计数器,当前状态为17,下一个状态必须是18


由于不变性条件以及后验条件在状态及状态转换上施加了各种约束,因此就需要额外的同步与封装。

①如果某些状态是无效的,那么必须对底层的状态变量进行封装,否则客户代码可能会使对象处于无效状态。

比如,变量只能取得正值,那么给客户的API就不能有使得状态变为负值的操作。

②如果在某个操作中存在无效的状态转换,那么该操作必须是原子的。

比如,有操作如果没有就添加值,这个操作在多线程的时候,可能出现由0个值,变为若干个值,这个时候必须保证检查值与设置值得操作是原子的。

③如果类中没有施加这种约束,那么就可以放宽封装性或序列化等需求,以便获得更高的灵活性或性能。



2.监视器模式

具体代码见P52

要点:

(1)一个类的状态虽然是可变的,但是由于变量的引用是final的,并且是private的,而能够访问状态的方法,都由内置锁保护。

(2)当然容器里面装的对象也是可变的,但是每次在返回这些对象的时候,都通过了一个深复制,保证了返回的对象的修改不会反映到原来的对象上,

并且返回的时候还要先装入Collections.unmodifiableMap()这样确保返回的map里面的内容不会被改变。

这样就确保了,整个的线程安全性。

这么做的优点是实现简单

缺点是由于要进行深复制,可能存在较大的性能损失。


注意:Collections.unmodifiableMap()表示的是,你不能通过这个引用去修改值,但是你能使引用指向其他的值,这个类似于C++的底层const引用。

由于它实际上是一个引用,所以它实际会反映出能够修改的对象,进行的修改。


3.委托模式

相对于监视器模式的本身对象是可变的,通过封装访问/改变对象的方法为synchoronized的,并且返回对象的深拷贝。

委托模式将线程安全性交给线程安全的容器来确保,所以叫做委托模式。

代码见P54

这里有三种:

①final的内置类型

②final的map

③final的unmodifiableMap

其中①可以随意发布

②能够对值进行修改

③相当于①,但是它能实时反映出别人的修改。


所以,返回时返回①或者③,修改时使用封装好的②的接口。


4.在现有的线程安全类中添加功能

(1)修改原始类

最为安全与高效,但是有时候没有办法办到,比如源码不可见或者非常复杂。

(2)扩展这个类---即extends

优点为简单,缺点是需要父类具有可扩展性,比如将状态向子类公开。相对于(1)更加脆弱

(3)客户端加锁机制---并不扩展类本身,而是把扩展代码放入一个辅助类中

缺点是必须使用与原来封装的类一样的锁。相对于(2)更加脆弱

(4)组合---通过再一次封装原来类型的所有方法

通过自身再完全封装一层锁实现线程安全。这个类似于监视器模式(只有通过封装过后的方法来访问原来的类)。

更加具有健壮性(统一使用了自身所规定的一种锁),并且性能损失很小(底层的原来的数据结构的访问不存在竞争)。


0 0
原创粉丝点击