一, 简述
竞态条件 (Race Condition): 计算的正确性取决于多个线程的交替执行时序时, 就会发生竞态条件.
二, 常见竞态条件分析
最常见的竞态条件为
1. 先检测后执行
执行依赖于检测的结果, 而检测结果依赖于多个线程的执行时序, 而多个线程的执行时序通常情况下是不固定不可判断的, 从而导致执行结果出现各种问题.
对于 main 线程, 如果文件 a 不存在, 则创建文件 a, 但是在判断文件 a 不存在之后, Task 线程创建了文件 a, 这时候先前的判断结果已经失效,(main 线程的执行依赖了一个错误的判断结果) 此时文件 a 已经存在了, 但是 main 线程还是会继续创建文件 a, 导致 Task 线程创建的文件 a 被覆盖, 文件中的内容丢失等等问题.
多线程环境中对同一个文件的操作要加锁.
2. 延迟初始化 (最典型即为单例)
- public class ObjFactory {
- private Obj instance;
- public Obj getInstance(){
- if(instance == null){
- instance = new Obj();
- }
- return instance;
- }
- }
线程 a 和线程 b 同时执行 getInstance(), 线程 a 看到 instance 为空, 创建了一个新的 Obj 对象, 此时线程 b 也需要判断 instance 是否为空, 此时的 instance 是否为空取决于不可预测的时序: 包括线程 a 创建 Obj 对象需要多长时间以及线程的调度方式, 如果 b 检测时, instance 为空, 那么 b 也会创建一个 instance 对象
和大多数并发错误一样, 竞态条件不总是会产生问题, 还需要不恰当的执行时序
三, 解决措施
Java 并发编程 (七): 线程安全策略 https://www.cnblogs.com/shamo89/p/10127180.html
来源: http://www.bubuko.com/infodetail-3106538.html