From the Java AtomicReferenceFieldUpdater
docs:
请注意,此类中
compareAndSet
方法的保证是 比其他原子类弱。因为这个班级无法保证 该领域的所有用途都适用于原子的目的 访问,它只能保证原子性和易失性语义 尊重compareAndSet
和set
的其他调用。
这意味着我无法与compareAndSet
一起执行常规易失性写入,但必须使用set
。它没有提到有关get
的任何内容。
这是否意味着我仍然可以读取具有相同原子性保证的易失性字段 - 所有写入set
或compareAndSet
之前的所有写入对于读取易失性字段的每个人都是可见的吗?
或者我必须在get
上使用AtomicReferenceFieldUpdater
而不是字段上的易失性读取吗?
如果您有参考,请发表参考文献。
谢谢。
编辑:
来自Java Concurrency in Practice,他们唯一说的是:
更新程序类的原子性保证弱于 普通的原子类因为你无法保证 底层字段不会直接修改 - compareAndSet 和算术方法只保证原子性相对于其他 线程使用原子字段更新器方法。
同样,没有提到其他线程应该如何读取这些易失性字段。
另外,我是否正确地假设“直接修改”是常规易失性写入?
答案 0 :(得分:2)
这意味着对对象的引用将得到保证,但因为您可以使用任何对象,当另一个线程访问该对象时,该对象的字段可能无法正确写入。
可以保证的唯一方法是字段是最终的还是不稳定的。
答案 1 :(得分:2)
这不是问题的确切答案:
文档中既没有解释也没有意图。如果想要绕过全局排序,即在允许它的体系结构上进行易失性写入(如IBM Power或ARM),并且只是暴露CAS(LoadLinked / StoreCondition)行为而不用屏障,那将是一个非常惊人的努力和混乱的来源。
sun.misc.Unsafe的CAS没有规范或排序保证(以前称为),但是java.util.atomic ...没有。所以在较弱的模型java.util.atomic impl上。在这种情况下需要必要的围栏来遵循java规范。
假设Updater类实际上没有围栏。
如果它们这样做,则易变的字段读取(不使用get)将返回更新值,即明确get()
是不需要的。由于没有订购保证,以前的商店可能不会传播(在弱模型上)。在x86 / Sparc TSO硬件上确保了java规范。
但是,这也意味着CAS可以使用以下非易失性读取进行重新排序。
java.util.concurrent.SynchronousQueue
队列中有一个有趣的注释:
// Note: item and mode fields don't need to be volatile
// since they are always written before, and read after,
// other volatile/atomic operations.
提到的所有原子操作都是AtomicReferenceFieldUpdater的CAS。这意味着正常的读写和AtomicReferenceFieldUpdater.CAS之间的缺乏或重写,即表现得像易失性写入。
s.item = null; // forget item
s.waiter = null; // forget thread
//....
while ((p = head) != null && p != past && p.isCancelled())
casHead(p, p.next);
只是CAS,没有易失性写入。
鉴于上述情况,我得出结论,AtomicXXXFieldUpdater暴露了与AtomicXXX对应物相同的语义。