我正在阅读一些有关Java中原子变量的文档。 正如到处所写的,AtomicInteger 应该是线程安全的。
根据我对原子整数的理解,它的工作原理是“比较和交换”算法。 我无法理解当两个线程尝试完全相同的时间增加同一个原子变量时,这将如何工作。 假设我已经定义了
AtomicInteger var = 1
,并且它被两个线程
Thread_1
和Thread_2
使用。当两个线程尝试同时增加 var
时会发生什么 T1
。
我知道这种情况很少见,但如果发生怎么办?在比较和交换中,它在单个原子操作中读取和更新变量,并检查内存中的值。那么,如果在时间 T1-1
,var 的值为 5 并且 Thread1
和 Thread2
都会开始递增它呢?
哪一个会失败?这会是随机行为吗?或者我错过了一些非常基本的东西。您可以使用比较和交换显式实现增量操作:
int value;
do {
value = var.get();
} while (!var.compareAndSwap(value, value + 1));
CPU 保证
compareAndSwap
是原子的(会有一个本机实现)。
如果两个线程同时命中此compareAndSwap
,则只有其中一个线程会“获胜”,接收
true
作为 compareAndSwap
调用的结果,因此循环停止。另一个线程将“失败”,并收到 false
作为结果,因此将再次循环:它读取一个新值,然后再次尝试 CAS。如果成功(因为没有其他线程同时尝试执行此操作,或者它“赢得”了另一个线程),则循环将停止;否则,它只会重试。
其中一个将成功执行与
5
的当前值和
6
的新值的比较和交换,另一个将失败并用6
的值和7
的新值重试。它们不能同时成功使用 5
的当前值和 6
的新值,它是在 CPU 级别处理的。 即使它们在不同的内核上运行并且 CAS 操作完全相同地执行,仍然有一个操作会失败,哪一个操作实际上是随机的(可能不取决于 CPU 实现)。