如何从scala伴生对象获取AtomicReferenceFieldDupDater?

如何从scala伴生对象获取AtomicReferenceFieldDupDater?,scala,concurrency,java.util.concurrent,Scala,Concurrency,Java.util.concurrent,如果我在某个集合结构中有一个链接节点,我真的不希望它的下一个链接是原子引用(我需要原子CAS更新),因此我将其声明为: @volatile var next: Node[A] = _n 然后在结伴声明中: val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[Link[_]], classOf[Node[_]], "n") def cas[A](target: Link[A], old: Node[A], newNode: N

如果我在某个集合结构中有一个链接节点,我真的不希望它的下一个链接是原子引用(我需要原子CAS更新),因此我将其声明为:

@volatile var next: Node[A] = _n
然后在结伴声明中:

val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[Link[_]], classOf[Node[_]], "n")
def cas[A](target: Link[A], old: Node[A], newNode: Node[A]) = updater.compareAndSet(target, old, newNode);
在运行时,我得到以下错误:

java.lang.RuntimeException: java.lang.IllegalAccessException: 
  Class concurrent.Link$ can not access a member of class concurrent.Link
  with modifiers "private volatile"
    at java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.<init>(AtomicReferenceFieldUpdater.java:189)
    at java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(AtomicReferenceFieldUpdater.java:65)
    at concurrent.Link$.<init>(Link.scala:106)
    ...
因此,除了在我的
链接
类上声明的
AtomicReferenceFieldDupdater
的静态实例之外,我拥有一切

问题是,如何在Scala中获得指向volatile var的
AtomicReferenceFieldDupdater
实例


到目前为止,我找到的唯一方法是回到Java(实现一个与下一个节点字段的抽象链接和一个静态的
AtomicReferenceFieldDupdater
)并从中继承,这很难看。

很难。由于Scala将字段设置为私有,并且只有访问器方法可用,所以这可能是不可能的

当我这样做的时候,我最终决定用volatile字段创建Java基类并在其中进行更新

Java文件:

public class Base {
   volatile Object field = null;
}
Scala文件:

class Cls extends Base {
  val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[Base[_]], classOf[Object[_]], "field")
  def cas[A](old: Object, n: Object) = updater.compareAndSet(this, old, n);
}

我还没有想出一种不同的方法。

有人告诉我,在纯scala中无法做到这一点,您需要在Java中定义一个类来做到这一点。幸运的是,交叉编译非常简单,但仍然很烦人

谢谢@axel22,我已经有了丑陋的Java黑客(见问题的最后一行),所以我无法给出答案。事实上,我重新阅读了您的解决方案,它遗漏了AtomicReferenceFieldDupDater的一个重要属性,那就是它是静态的。您希望在所有实例中共享同一个更新程序,这就是重点——否则您只需直接使用AtomicReference。这是一个讨论的主题——将其作为私有字段实际上可能比作为静态引用更便宜,并且必须对此进行基准测试。在任何情况下,它都应该比把它放在一个伴生对象中要便宜。就内存而言,拥有静态内存肯定要便宜。每个节点只会创建一个对象,而不是两个,因此很难看出私有节点的成本会如何降低。就调用cas所需的时间而言,成本会降低。只创建一次对象,但通常会多次访问它。将更新程序放在伴随对象中意味着要访问它,需要首先获取伴随对象引用,然后调用它上的getter来获取更新程序。拥有一个私有字段相当于一个间接寻址。这样可以减少一次缓存未命中。您可以始终实例化更新程序一次,并将对它的引用放在所有
Cls
对象中。不过,我还是会做一个微基准来验证这个假设。
class Cls extends Base {
  val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[Base[_]], classOf[Object[_]], "field")
  def cas[A](old: Object, n: Object) = updater.compareAndSet(this, old, n);
}