3

我正在阅读一些关于 Java 中原子变量的文档。正如到处都写的那样,AtomicInteger 应该是线程安全的。

根据我对原子整数的理解,它的工作原理是比较和交换算法。当两个线程尝试在完全相同的时间增加相同的原子变量时,我无法理解这将如何工作。

说我有定义AtomicInteger var = 1,这被两个线程Thread_1Thread_2. var当两个线程同时尝试增加 时会发生什么T1。我知道这将是罕见的情况,但如果它发生了怎么办。在比较和交换中,它在单个原子操作中读取和更新变量,并检查内存中的值。那么如果在 time T1-1, var 的值是 5 并且两者都Thread1Thread2开始递增呢?哪一个会失败?会是随机行为吗?或者我错过了一些非常基本的东西。

4

3 回答 3

6

比较和交换在 CPU 级别是原子的。

您可以使用比较和交换显式实现增量操作:

int value;
do { 
  value = var.get();
} while (!var.compareAndSwap(value, value + 1));

CPU 保证它compareAndSwap是原子的(会有一个本机实现)。

如果两个线程同时命中这个compareAndSwap,只有其中一个会“获胜”,true作为compareAndSwap调用的结果接收,所以循环停止。

另一个线程将“丢失”并接收false结果,因此将再次循环:它读取一个新值,然后再次尝试 CAS。如果成功(因为没有其他线程同时尝试执行此操作,或者它“胜过”另一个线程),则循环停止;否则,它只是再次尝试。

于 2019-05-20T07:53:43.940 回答
3

那么如果在时间 T1-1,var 的值为 5 并且 Thread1 和 Thread2 都将开始递增呢?

其中一个将成功执行与当前值5和新值的比较和交换6,另一个将失败并使用 的值6和新值重试7。它们不能同时使用 的当前值5和新值成功6,它是在 CPU 级别处理的。

即使它们在不同的内核上运行并且 CAS 操作在完全相同的时间执行,仍然有一个操作会失败,哪个操作实际上是随机的(可能不取决于 CPU 实现)。

于 2019-05-20T07:54:15.857 回答
2

这是典型的比赛条件情况。将此增量操作视为带有小门的小房间,其中只有一个人可以容纳并执行一些操作。两个设法进入这个房间的第一个线程将执行增量操作。然后当它完成时,第二个=“不太幸运”线程将完成它的工作。但重要的是,两个操作的结果是一致的,因为它们不会并行执行增量操作。

于 2019-05-20T07:48:29.273 回答