Volatile arrays

The volatile variable rule from the Java Memory Model, makes sure that there is a happens before relation between a write and read of a volatile variable. This makes it possible to exchange not just values of primitive types between threads, but also complete object graphs without adding the burden of safe publication to each objects in the graph. So volatiles variables are a nice tool in the concurrency toolbox.

But it is not possible to create an array of volatile elements, So if an array element is written by one thread and read by another, some happens before relation needs to be added. Declaring the array reference volatile has no effect, because a happens before relation only exists between a write and a read of a volatile variable, and not between 2 reads.

You could add a synchronized block to introduce the happens before relation (monitor lock rule):

final int[] array = ...;

void write(int index, int value){
	array[index]=value;
	synchronized(this){}//does the monitor.unlock
}

void read(int index){
	synchronized(this){}//does the monitor.lock
	return array[index];
}

But it isn’t the prettiest solution because it could lead to expensive operating system calls. Just doing a dummy write and read to a volatile variable, could also introduce the desired happens before relation:

final int[] array = ...;
volatile boolean barrier;

void write(int index, int value){
	array[index]=value;
	barrier = true;//the volatile write
}

int read(int index){
	boolean b = barrier;//the volatile read
	return array[index];
}

Volatile variables have less overhead than locks, but it still isn’t perfect because a happens before relation is created between a write and read of different elements. This unneeded happens before relation could influence the performance of the cache. So it would be better if only happens before relations are added where needed. To be honest, I don’t have got numbers to back it up and I also don’t have access to serious hardware (with a lot of cores) to create benchmarks. What could work well on my dual core Intel machine, could behave terrible on a serious multi-processor environment.

Another solution would be to create an array of volatile wrapper objects:

class VolatileInt{
   volatile int value;
}


final VolatileInt[] array = create(10);

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

void write(int index, int value){
	array[index].value = value;
}

int read(int index){
	return array[index].value;
}

It increases the size of the array in memory, and it adds some overhead because an extra field access needs to be done, but you have complete control on the number of happens before relations.

Luckily volatile arrays are not a problem people encounter frequently.

ps:
even though the introduced volatile write/read or synchronized(this){} add no visible value to the executing thread, it can’t be removed by the compiler because it does add a happens before relations.

Leave a comment