如何在Java中声明数组元素?

如何在Java中声明数组元素?,java,arrays,concurrency,volatile,Java,Arrays,Concurrency,Volatile,有没有一种方法可以在Java中声明数组元素volatile?即 volatile int[] a = new int[10]; 声明数组引用volatile,但数组元素(例如a[1])仍然不是volatile。所以我在找类似的东西 volatile int[] a = new volatile int[10]; 但不是这样的。有可能吗?使用AtomicIntegerArray或AtomicLongArray或AtomicReferenceArray AtomicIntegerArray类实现

有没有一种方法可以在Java中声明数组元素
volatile
?即

volatile int[] a = new int[10];
声明数组引用
volatile
,但数组元素(例如
a[1]
)仍然不是volatile。所以我在找类似的东西

volatile int[] a = new volatile int[10];

但不是这样的。有可能吗?

使用
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray

AtomicIntegerArray
类实现了一个int数组,通过该类的
get()
set()
方法,可以使用volatile语义访问该数组的各个字段。从一个线程调用
arr.set(x,y)
将保证调用
arr.get(x)
的另一个线程将读取值y(直到另一个值被读取到位置x)

见:

  • 包摘要

不,不能使数组元素易变。另请参见。

另一种方法是使用JDK 9+类。正如您在
Atomic
xxx
Array
类的源代码中所看到的,这些类也使用
VarHandle
,因为JDK 9:

//[...]

private static final VarHandle AA
    = MethodHandles.arrayElementVarHandle(int[].class);
private final int[] array;

//[...]

/**
 * Returns the current value of the element at index {@code i},
 * with memory effects as specified by {@link VarHandle#getVolatile}.
 *
 * @param i the index
 * @return the current value
 */
public final int get(int i) {
    return (int)AA.getVolatile(array, i);
}

/**
 * Sets the element at index {@code i} to {@code newValue},
 * with memory effects as specified by {@link VarHandle#setVolatile}.
 *
 * @param i the index
 * @param newValue the new value
 */
public final void set(int i, int newValue) {
    AA.setVolatile(array, i, newValue);
}

//[...]
首先创建一个
VarHandle
,如下所示:

MethodHandles.arrayElementVarHandle(yourArrayClass)
例如,您可以在此处输入
byte[].class
,自己实现缺少的
AtomicByteArray

然后,您可以使用
set
xxx
(数组,索引,值)
get
xxx
(数组,索引)
方法访问它,其中
array
的类型为
yourrarrayclass
index
的类型为
int
value
的类型为数组中的元素(
yourArrayClass.getComponentType()

请注意,例如,如果
yourArrayClass==byte[].class
但输入
42
作为
,则会出现错误,因为
42
int
而不是
byte
,并且访问方法的参数是vararg
对象…
参数:

java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(VarHandle,byte[],int,byte)void to (VarHandle,byte[],int,int)void
(第二个签名是您使用的,第一个签名是您应该使用的。)


请注意,JDK 8及以下版本中用于实现原子类,如:

(现在应该修复了)

这个怎么样:

static class Cell<T> {
        volatile T elem;
    }

private Cell<T>[] alloc(int size){
        Cell<T>[] cells = (Cell<T>[]) (new Cell[size]);
        return cells;
    }

 volatile Cell<T>[] arr;
 Cell<T>[] newarr = alloc(16);
 for (int i = 0; i < newarr.length; i++) {
      newarr[i] = new Cell<>();
 }
 arr = newarr;
静态类单元格{
挥发性T元素;
}
专用单元格[]alloc(整数大小){
单元格[]单元格=(单元格[])(新单元格[大小]);
返回单元;
}
挥发性细胞[]arr;
单元格[]newarr=alloc(16);
for(int i=0;i

单元格也会使内容变得不稳定。另外,我只有在预先分配单元格后才将新数组分配给不稳定的数组……单元格额外内存有一个折衷,但它是可管理的

实际上你可以,但需要额外的努力。从技术上讲,这仍然不会使元素变得不稳定,但数组操作是不稳定的。Since
int
对于这种情况,它是一个原语,它本质上具有相同的行为,但对于非原语数组,这不容易扩展。我想知道为什么对于int和long,有特定的
atomicarray
,但对于其他原语类型,却没有……当然,其他原语可以通过在n
AtomicReferenceArray
。我认为AtomicIntegerArray和AtomicLongArray经过优化,可以分别处理integer和long。@JoonasPulakka对于其他基本类型,您也可以使用例如
Float.floatToIntBits(Float)将它们转换为int或long
。这避免了在使用
AtomicReferenceArray
@Kanagavelu-Sugumar时需要装箱:AtomicReference是一个包装的
volatile
,带有一些额外的方法(getAndSet等)。是的,您可以使数组变为volatile。请参阅此-
java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(VarHandle,byte[],int,byte)void to (VarHandle,Object[])void
static class Cell<T> {
        volatile T elem;
    }

private Cell<T>[] alloc(int size){
        Cell<T>[] cells = (Cell<T>[]) (new Cell[size]);
        return cells;
    }

 volatile Cell<T>[] arr;
 Cell<T>[] newarr = alloc(16);
 for (int i = 0; i < newarr.length; i++) {
      newarr[i] = new Cell<>();
 }
 arr = newarr;