• 线程安全类中封装了必要的同步机制,因此在客户端无需进一步采取同步措施
  • 无状态对象一定是线程安全的 - StatelessFactorizer

    原子性 2.2

  • 竞态条件:由于不恰当的执行时序而出现不正确的结果 - UnsafeCountingFactorizer,LazyInitRace

    1. “先检查后执行” 操作 * 复合操作 - CountingFactorizer
  • 要保证复合操作必须是原子的

例:读取 - 修改 - 写入 这三个操作(符合操作)是原子的 要多实用现有的线程安全对象(如 AtomicLong)管理类的状态

加锁机制 2.3

  1. 条件:当状态从1个变成多个时,线程安全状态变量并不是从1个变成多个那么简单 - UnsafeCachingFactorizer <br /> 要保持状态的一致性,就需要在单个原子操作中,更新所有的相关状态
  • 内置锁 - SynchronizedFactorizer

    1. 互斥体(互斥锁)
  • 重入 - nonreentrantDeadLock.java

    1. 为解决子类改写父类的同步方法产生死锁,必须使用重入的锁,即在继承是也加上同步关键字重入获取锁锁的操作的粒度是线程而不是调用<br />

    用锁来保护状态 2.4

  • 对于可能被多个线程同时访问的可变状态变量,在访问他是需要持有同一个锁,在这种情况下,我们称状态变量是由这个锁保护的
  • 每个共享的和可变的变量都应该只由一个锁来保护,从而使维护人员知道是哪一个锁
  • 对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护

例:虽然vector的所有方法都是同步方法,但是复合操作还是要加锁 (put-if-absent) :::tips 参考4.4节:了解如何在线程安全对象中添如原子操作的方法 :::

活跃性与性能 2.5 - CachedFactorizer

  1. 通常:在简单性与性能之间存在着相互制约因素,当实现某个同步策略时,一定不要盲目地为了性能二牺牲简单性(这可能会破坏安全性) 当执行时间较长的计算或者可能无法快速完成操作时(例如:网络I/O或控制台I/O),一定不要持有锁。<br />

:::tips 补充: 竞态条件 容易与 数据竞争 相混淆,可看16章,了解 数据竞争 :::