1、什么是线程安全性
从一开始就设计一个线程安全的类,比在以后再将这个类修改为线程安全的类要容易的多。
线程安全的类中封装了必要的同步机制,因此客户端无需进一步采取同步措施。
无状态对象一定是线程安全的(不包含任何域和其他类的引用,只有线程局部变量)
2、原子性
int类型也非原子,++count包含了读取,修改,写入的操作序列。
2.1、竞态条件
UnsafeCountingFactorizer
最常见的竞态条件类型是:先检查后执行操作,即通过一个可能失效的观测结果来决定下一步的动作。
2.2、示例:惰性初始化中的竞态条件
LazyInitRace
单利模式的懒惰模式如果没有加同步,多线程可能产生不同的对象实例
2.3、复合操作
要避免竞态条件问题,就必须在某个线程修改该变量时,通过某种方式防止其他线程使用这个变量,也就是让其变成原子操作(两个线程互斥)
在实际情况中,应该尽可能使用现有线程安全对象
如AtomicLong来管理类的状态。
3、加锁机制
为了保护状态的一致性,要在单一的原子操作中更新相互关联的状态变量。
3.1、内置锁
synchronized块,是互斥锁(mutual exclusion lock,也称作mutex)。
3.2、重入(Reentrancy)
内置锁是可重入的,防止一下这种情况导致的死锁:
重入锁的请求是基于每个线程的,而不是每个调用;通过为每个锁关联一个请求计数和一个占有它的线程实现的。
4、用锁来保护状态
如果用同步来协调访问变量,每次访问变量时,都需要同步,每次访问变量都需要同一个锁。