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