Using volatile collections and arrays in Java Baeldung

Let's pretend that

volatile int publisher = 0;
volatile List<String> list = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
volatile String[] array = {"Buenos Aires", "Córdoba", "La Plata"};

      

As far as I understand.

The original values ​​in the list and array are published correctly and are visible to all read streams.

All values ​​added after initialization are not published securely.

However, we can safely read and publish them using

//in Thread 1
list.add("Safe City");
array[2] = "Safe city";
publisher = 1;

//in Thread2

if(publisher == 1) {
String city = list.get(3);
city = array[2];
}

      

I'm right?

+3


source to share


5 answers


That's right, but ...

The keyword volatile

in the list and array doesn't matter here - the fact that you write the value in volatile

publisher

after , you write other values ​​and read that the value in your ìf

state before , reading other values ​​in the second thread, ensures consistency between those threads.

If you remove the keyword volatile

from the list and array, your code is still safe.



If you delete the write / read of the variable publisher

, then the add

* operation and array assignment are safer.

And yes, initial variable assignment is also safe.

* which is actually not valid in that particular listing anyway as pointed out by Stuart Mark, but let's say his. ArrayList

+4


source


Looking strictly at what the code does and nothing more, and only evaluating it in terms of the memory model, you are correct. Writing to a volatile variable publisher

on stream 1 and reading from a volatile variable on stream 2 establish communication between events, so all previous writes from stream 1 will be visible for subsequent reads from stream 2.

As CupawnTae pointed out, there is no need for the list and array to be volatile for this to hold. It just publisher

needs to be unstable.

Looking at it from a broader perspective, it is very difficult to extend this code to do anything else. (Reverse the fact that the List

returned Arrays.asList

item cannot contain items added to it, take instead instead ArrayList

.) Presumably thread 1 or some other thread will want to continue adding items to the list, If it does, to ArrayList

reallocate its underlying array, this can happen while thread 2 is still reading the results of the previous append. So the inconsistent state can be visible for thread 2.



Suppose further that thread 1 wants to make subsequent updates. It will have publisher

to be set to some other value, say 2. Now, how are reading topics read, why do you need to check the correct value? Well, they can read the expected value from some other volatile variable ....

Sure, it is possible to build a scheme where thread 1 can write to a list (or array) at will, and thread 2 will never see anything other than consistent snapshots, but you have to be extremely careful about memory visibility every step of the way. At some point, it's easier to just use locks.

+6


source


"Publishing" occurs between the thread that sets the mutable value and the thread that receives it.

You need both

publisher = 1;

      

in one stream and

int local = publisher;

      

in another.

0


source


Have you considered using blocks synchronized

to lock the data structures you are trying to read / write to / from?

//in Thread 1
synchronized(someLockingMonitor) {
    list.add("Safe City");
    array[2] = "Safe city";
}

//in Thread2
synchronized(someLockingMonitor) {
    String city = list.get(3);
    city = array[2];
}

      

However, this will cause any thread wishing to access one of the blocks to wait until some other thread currently executing inside one of those blocks leaves the block.

If concurrency is important to you, that is, you really want different reads and writes of threads at the same time, look at parallel collections in java.util.concurrent

.

0


source


I know that volatile only works on object reference, but not on changing the contents of the mutable object.

But can anyone show us an example to demonstrate the volatile array problem.

I followed the example at    https://javax0.wordpress.com/2016/09/21/final-volatile/

public class VolatileDemonstration implements Runnable {
@Override
public void run() {
    System.out.println(getFirst());
    while (getFirst() == 0);
    System.out.println(getFirst());
}

public VolatileDemonstration() throws InterruptedException {
    new Thread(this).start();
    Thread.sleep(1000);
    setFirst(1);
}

public static void main(String[] args) throws InterruptedException {
    new VolatileDemonstration();
}

private volatile int[] arr = new int[20];

public int getFirst() {
    return arr[0];
}

public void setFirst(int n) {
    arr[0] = n;
}
}

      

But the problem does not hang ...

0


source







All Articles