代码之家  ›  专栏  ›  技术社区  ›  Joonas Pulakka

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

  •  32
  • Joonas Pulakka  · 技术社区  · 14 年前

    有没有办法声明数组元素 volatile 在爪哇?即。

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

    数组引用 不稳定的 ,但 数组元素 (例如。 a[1]

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

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

    4 回复  |  直到 14 年前
        1
  •  32
  •   uthark    7 年前

    使用 AtomicIntegerArray AtomicLongArray AtomicReferenceArray

    原子整数阵 类实现一个int数组,通过类的 get() set() 方法。使命感 arr.set(x, y) 来自一个线程的消息将保证另一个线程调用 arr.get(x)

    见:

        2
  •  6
  •   Tim Jansen    14 年前
        3
  •  6
  •   SWdV sloth    5 年前

    VarHandle 班级。正如您在 Atomic xxx Array AtomicIntegerArray ,这些类也使用 瓦汉德尔

    //[...]
    
    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);
    }
    
    //[...]
    

    首先创建一个 瓦汉德尔 这样地:

    MethodHandles.arrayElementVarHandle(yourArrayClass)
    

    例如,您可以输入 byte[].class AtomicByteArray 你自己

    然后您可以使用 set xxx (array, index, value) get xxx (array, index) array 是一种 yourArrayClass , index 是一种 int , value 是数组中元素的类型( yourArrayClass.getComponentType()

    请注意,例如, yourArrayClass == byte[].class 但是你进去了 42 价值 ,您将得到一个错误,因为 是一个 而不是 byte Object... 参数:

    java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(VarHandle,byte[],int,byte)void to (VarHandle,byte[],int,int)void
    


    请注意,在JDK 8及以下版本中 sun.misc.Unsafe AtomicIntegerArray :

    //[...]
    
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final int base = unsafe.arrayBaseOffset(int[].class);
    private static final int shift;
    private final int[] array;
    
    static {
        int scale = unsafe.arrayIndexScale(int[].class);
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }
    
    private long checkedByteOffset(int i) {
        if (i < 0 || i >= array.length)
            throw new IndexOutOfBoundsException("index " + i);
    
        return byteOffset(i);
    }
    
    private static long byteOffset(int i) {
        return ((long) i << shift) + base;
    }
    
    //[...]
    
    /**
     * Gets the current value at position {@code i}.
     *
     * @param i the index
     * @return the current value
     */
    public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }
    
    private int getRaw(long offset) {
        return unsafe.getIntVolatile(array, offset);
    }
    
    /**
     * Sets the element at position {@code i} to the given value.
     *
     * @param i the index
     * @param newValue the new value
     */
    public final void set(int i, int newValue) {
        unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
    }
    
    //[...]
    

    使用 Unsafe 仍然是一个选项(尽管我认为获取实例有点棘手),但不鼓励这样做,因为您必须自己检查数组边界,如果您出错,它可能会导致Java进程出错,而 瓦汉德尔 不安全的 不受官方支持,可能随时被删除。

    不安全的 仍在使用中 AtomicInteger 因为 .


    Using JDK 9 Memory Order Modes (我不得不说,我根本不是这方面的专家(到目前为止?)。


    请注意,从今天起,您不能使用 在Kotlin,因为它包裹了vararg 对象 Object[] 看见 bug KT-26165

    java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(VarHandle,byte[],int,byte)void to (VarHandle,Object[])void
    

    (现在应该修复)

        4
  •  0
  •   gotch4    5 年前

    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;
    

    这些细胞也会使内容不稳定。另外,我只在预先分配单元后才将新数组分配给易失性数组。。。有一个折衷的细胞额外的内存,但它是可管理的