简体   繁体   中英

Java volatile array?

How do I make an array volatile? Because as I've come to understand, it's unsafe to make an array volatile?

Declaring an array volatile does not give volatile access to its fields. You're declaring the reference itself volatile, not its elements.
In other words, you're declaring a volatile set of elements, not a set of volatile elements .

The solution here is to use AtomicIntegerArray in case you want to use integers. Another way (but kinda ugly) is to rewrite the reference to the array every time you edit a field.

You do that by:

arr = arr; 

(as I said... ugly)

AtomicLongArray、AtomicIntegerArray、AtomicReferenceArray (java.util.concurrent.atomic)。

EDIT: Arrays are objects in java. If you make the reference to that object volatile, makes it visible to other threads if you exchange the reference to the array. However this does not hold for the array values themselves.

Getting a better understanding of the java memory model, there is actually a possibility to get around it without an Atomic*Array. Using the happened-before relationship for volatile reads and normal writes makes it possible:

If thread A writes some non-volatile stuff and a volatile variable after that, thread B is guaranteed to see the changes of the non-volatile stuff as well, but only if thread B reads the volatile variable first. see also: Happens-before relationships with volatile fields and synchronized blocks in Java - and their impact on non-volatile variables?

For arrays, this means: After you write to the array, write to some volatile status variable (make sure the write actually changes the volatile status variable!) When you read from the array, read the volatile status variable first, and then access the array. The volatile read should make all other writes visible as well, as long as they happened before.

OLD: writing the self reference arr=arr wouldn't actually help.

You write the address of the array arr , not the value of the field arr[i] . So you still gain no volatile properties for arr[i] (which you want), but only for the storage address arr .

The previously mentioned blogpost of Jeremy Manson explains it in detail: http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html

His best solution is to use Atomic*Arrays, namely the AtomicReferenceArray for generic types (there also exist special forms for basic types). I can't imagine that this is particularly efficient, especially as it gains you more properties that you need (atomicity >> volatile).

An alternative may be pointered structures where the containers use volatile pointer fields. Also not that efficient ...

How about this:

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;

the cells make the content volatile too. also I assign the new array to the volatile one only after pre allocating the cells... there's the trade off of the Cell extra memory, but it's manageable

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM