使用组合模式能够使一个类更容易成为线程安全的。

4.1 设计线程安全的类 - Counter

  1. 在设计线程安全类的过程中,需要包含以下三个基本要素:
  1. 找出构成对象状态的所有变量
  2. 找出约束变量的不变性条件
  3. 建立对象状态的并发访问管理策略

    4.1.1 收集同步需求

    如果不了解对象的不变性条件与后验条件,那么就不能确保线程安全性,要满足在状态变量的有效值或状态转换上的各种约束条件,就需要借助原子性与封装性。

    4.1.2 依赖状态的操作

    在某些对象的方法中包含一些先验条件。如不能从空队列中一处一个元素。
    简单实现先验条件的方法就是通过现有库中的类(阻塞队列(Bloking Queue)、信号量(Semaphore))
    第5章介绍一些阻塞类
    第14章介绍如何使用平台与类库提供的各种底层机制创建依赖状态的类

    4.2 实例封闭 - PersonSet

    1. 将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁 ,封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类类的线程安全性时就无须检查整个程序

    4.2.1 Java监视器模式 - PrivateLock

     Java监视器仅仅是一种约定,对于任何一种锁对象,只要自始至终都使用该锁对象,都可以用来保护对象的状态        <br />Java监视器模式优点:私有的锁对象可以将锁封装起来,使客户代码无法获得锁,但客户代码可以通过公有方法来访问锁,以便(正确或者不正确地)参与到它的同步策略中。
    

    4.2.2 实例:车辆追踪 - MonitorVehicleTracker, MutablePointer

    4.3 线程安全性的委托

     对于多个非线程安全的类组合一个类时,Java监视器模式是非常有用的。但是如果类中的各个组件都是线程安全的,则这是一个好的开端。    
    

    4.3.1 实例:基于委托的车辆追踪器 - PointDelegatingVehicleTracker

     委托给线程安全的Map中
    

    4.3.2 独立的状态变量 - VisualComponent

     我们可以将线程安全性委托给多个状态变量,只要这些变量是彼此独立的,即组合而成的类并不会在其包含的多个状态变量上增加任何不变性条件。
    

    4.3.3 当委托失效时 - NumberRange

     如果一个类是由多个独立且安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层的状态变量。
    

    4.3.4 发布底层的状态变变量

    如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态装换,那么就可以安全地发布这个变量

    4.3.5 示例:发布状态的车辆追踪器 - PublishingVehicleTrackerSafePoint

4.4 在现有的线程安全类中添加功能 - BetterVector

    方法一:添加一个新的原子操作,最安全的方法是修改原始类,但这通常无法做到,因为你可能无法访问或修改类的源代码。       <br />     方法二:扩展原始类-继承的方式   

4.4.1 客户端加锁 - ListHelper.BadListHelper, ListHelper.GoodListHelper

    方法三:使用辅助类-将安全容器当做辅助类的属性,记住加锁的位置-应该锁住安全容器,而不是辅助类的方法        <br />必须使List在实现客户端加锁或外部加锁时使用同一个锁。要使用客户端加锁,你必须知道对象X使用的是哪一个锁。        <br />该扩展会破坏实现的封装性,客户端加锁同样会破坏同步策略的封装性。

4.4.2 组合

使用了Java监视器模式来封装现有的List,并且只要指向底层List的唯一外部引用,就能确保线程安全性。