【问题标题】:alternatives for volatile array易失性数组的替代品
【发布时间】:2013-04-01 08:12:56
【问题描述】:

从其他问题中,我了解到 volatile 数组的元素不是 volatile。只有引用本身是可变的。

volatile[] int data;

Thread A: data[4] = 457;
Thread B: System.out.println(data[4]);

这里,线程 B 可能永远看不到更新的值。

我必须使用哪些选项/替代方案来实现相同的目标?我想避免必须同步数组,因为它几乎没有被改变过。但是,一些线程正在阅读它。同步它很可能会降低吞吐量,这在本示例中非常重要。

我唯一的选择是写时复制数据结构吗?也就是将数组复制到一个新数组中,然后更新数组引用。

还有其他选择吗?我在某处读到将数组封装到一个类中(只有一个成员,数组)实现了同样的事情,但我怀疑这是真的。我看不出这有什么帮助。

请注意,我的目标 JVM 是 1.4。这意味着我不能使用 java.util.concurrent 包。

--------------编辑编辑编辑--------------

Java volatile array? 中,我读到重新分配数组引用实现了易失性语义。这应该会给出正确的结果:

volatile[] int data;

Thread A: data[4] = 457;
Thread A: data = data;
Thread B: System.out.println(data[4]);

这在旧版 JVM 上有效吗?

【问题讨论】:

  • 我更新了我的问题。请参阅下面的编辑行。
  • 您确定需要避免同步吗?你说同步它“很可能会降低吞吐量” - 好的,但也许你应该编写同步代码并对其进行基准测试以了解性能是否正常(即尽量避免过早优化?)
  • 我很确定它会的。我的目标是一个旧的 JVM,并且过去通过用写时复制数据结构和易失性访问替换同步来提高性能。我想在这里做同样的事情。
  • 这个怎么样:每个线程是否可以保存数组的完整副本,并且您可以在数据更改时(不经常)通过在每个线程上使用回调或其他更新函数来更新每个线程的副本? (或者使用 volatile bool 来标记线程何时应该从主副本更新其值?)
  • 这是一个非常有用的评论,聪明的主意。我会考虑的。非常感谢。你也看到我的编辑了吗?这行得通吗?

标签: java arrays synchronized volatile java1.4


【解决方案1】:

数组被标记为 volatile,即只有引用被标记为 volatile。数组本身的元素根本不继承 volatile 关键字的内存可见性语义。

我可以建议您自己构建一个AtomicIntergerArray 类。您可以在哪里保留 final int[] data 参考并正确同步。

也可以看看AtomicIntergerArrayimplementation code

否则你可以使用Backport apiAtomicIntegerArray

该项目旨在提供一个并发库,该库可在当前使用的所有 Java 平台上以不折不扣的性能工作,从而允许开发完全可移植的并发应用程序。更准确地说,traget 范围是 Java 1.3 及更高版本,如果为 Java 1.2 提供一些有限的支持。

【讨论】:

  • 请阅读我的问题。 :) 我想避免同步。
  • 其实我读过,但我找不到任何其他方法来实现它。或者你可以使用 backport api 的AtomicIntegerArray
  • 谢谢。 “问题”是这些反向移植 API 使用同步,我想在这里避免这种情况。我需要通过很多线程来访问这个数组,并且鉴于数组几乎没有更新,我应该尝试消除同步锁。
【解决方案2】:

只需使用包装器:

class VolatileInt{
    volatile int value;
}

VolatileInt[] create(int size){
    VolatileInt[] array = new VolatileInt[size];
    for(int k=0;k<size;k++)
        array[k]=new VolatileInt();
    return array; 
}

VolatileInt[] array = create(10);

【讨论】:

    【解决方案3】:

    使用arr=arr管理Java重写数组的存储地址(数组在Java中也是对象)。数组字段arr[i] 没有获得 volatile 属性。

    在某些情况下,arr=arr 可能会出于未知原因起作用,但它不会让您安全。

    如果您想保持安全,请使用Atomic*Array 的东西。是的,额外的原子性代价高昂,但我想如果您考虑访问时间和存储空间,它比链接结构更好。

    如果您想避免全局锁,您可以考虑将数组拆分为子集。这使得锁只影响一个子集,你仍然保持所有值的波动性。

    我分享你的问题,最好是Atomic*Arrays

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-07
      • 2011-07-07
      • 1970-01-01
      • 2014-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      相关资源
      最近更新 更多