竞态条件指的是不恰当的线程执行时序导致产生不正确的结果。
常见情况有“先检查后执行”。即通过一个可能失效的观测结果来决定下一步的动作。比如线程A检查文件X是否存在,若发现不存在,则创建一个新的文件X。但这个观测结果可能无效,比如在观测到文件不存在到创建文件期间,线程B创建了文件X,会导致各种问题。
“先检查后执行”的情况在延迟初始化中也会遇到。延迟初始化指在需要用到对象时才进行初始化。比如在单例模式中线程A检查实例Y是否存在,不存在则创建实例。在检查与创建过程中线程B可能也检查并创建实例,导致出现问题。
还有一种情况是类似“读取--操作--写入”。比如java中的自增操作。在线程A读取变量i但还未来得及写入时,线程B也读取变量i,导致AB线程都完成后变量i只增加了一次,而不是期望的两次。
如果操作涉及多个变量,需要在单个原子操作中完成所有相关变量的操作。
例如涉及两个实例A和B的延迟初始化,需要同时对AB进行检查并初始化。仅仅将A和B的初始化过程分别原子化是不够的。线程1先初始化A再初始化B,在这两个原子操作之间线程2仍然可以对B检查并初始化。若要达到期望的效果,需要将AB的初始化过程整合成单个的原子操作。