线性安全-原子性

118 阅读1分钟

竞态条件

某个计算的正确性取决于多个线程交替执行的时序。

常见的竞态条件有两种

  1. 读-改-写
  2. 检查-执行

读-改-写

当n个线程并发调用selfCount方法时,cuont最后的结果很大概率小于n。

public class ReadUpdateWrite {
    private int count = 0;
    
    public void selfCount() {
        count++;
    }
}

检查-执行

在多线程并发环境下,instance很有可能被实例化多次,从而引发不可预测的错误。

public class LazyInitRace {
    private Object instance = null;
    
    public Object getInstance() {
        if (instance == null) {
            instance = new Object();
        }
        return instance;
    }
}

原子性

原子操作

假定有操作A和操作B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。

原子操作是指,以原子方式执行访问同一个状态的所有操作。换句话说,操作具有原子性。

原子操作意义

解决竞态条件导致的线程安全问题。

如何实现原子操作

实现原子操作,最直观最简单的方法就是加锁。

Java中的锁实现有内置锁synchronized和显式锁Lock

上面的两个例子,使用内置锁进行改造如下,即可保证线程安全。

public class ReadUpdateWrite {
    private int count = 0;
    
    public synchronized void selfCount() {
        count++;
    }
}

public class LazyInitRace {
    private Object instance = null;
    
    public synchronized Object getInstance() {
        if (instance == null) {
            instance = new Object();
        }
        return instance;
    }
}