Semghh

原子性修改数组元素引发的思考

2025-02-18

1. 赋值操作-原子性

64位虚拟机的引用是64bit或32bit(开启指针压缩,堆内存无法超过32GB),因此一次赋值操作(=)是原子的。

2. “可见性”

原子操作、和可见性经常被同时提及。

2.1 无需保证可见性的场景

但两者是完全不同的语义,并且大多数场景下,我们只需要保证update操作的原子性,而不需要保证严格的“及时”。

所谓严格的及时指 “可见性保证”。

修改者改变了某个值,但读取者无需立即知道新的值(也就是,在业务上使用稍过期的值并没有什么问题)。此时我们可以不使用volatile(也就是无需保证可见性)

2.2 需要保证可见性的场景

假设,我们有一个long[]数组, 我们通过Unsafe可以很轻易地做到 atomic + volatie的修改其中一个long元素。

如果业务有如下要求, index为N的元素和 index为N-1的元素有关联,两者共同组成了一种业务语义。

并且这个long[]数组整体是共享的,那么我们必须要保证元素的可见性。

因为我们不可能拿新的index=N的元素和旧的index=N-1的元素共同表达业务语义。

这和32bit虚拟机无法保证 long类型的赋值操作是”原子性”的原因类似——后32bit和前32bit是一个整体,我们不应当看见一个 “牛头马尾”。而是一个完整的牛或马。

2.2.1 如何解决上述场景

转换一下思维,若 long1和long2组成一个整体,我们把它定义为一个新的ClassA。

将long[] 改为 A[],然后” 原子性” 且 “volatile” 的修改元素。

缺点是引入了一个新的Class,带来了额外开销。

参考


Similar Posts

Comments