Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to volatile fields through local variables

This question is somewhat continuation and expansion of this one, as I think perfect question: How does assigning to a local variable help here?

This question based on Item 71 of Effective Java, where it is suggested to speed up performance by introducing local variable in purpose of volatile field access:

private volatile FieldType field;  
FieldType getField() {  
    FieldType result = field;  
    if (result == null) { // First check (no locking)  
        synchronized(this) {   
        result = field;  
        if (result == null) // Second check (with locking)  
            field = result = computeFieldValue();  
        }  
    }  
    return result;  
}

So, my question is more common:

should we always access to volatile fields through assigning their values to local variables? (in order to archive best performance).

I.e. some idiom:

  1. we have some volatile field, call it just volatileField;

  2. if we want to read its value in multi-thread method, we should:

    1. create local variable with same type: localVolatileVariable
    2. assign value of volatile field: localVolatileVariable = volatileField
    3. read value from this local copy, e.g.:

      if (localVolatileVariable != null) { ... }
      
like image 807
Andremoniy Avatar asked Apr 19 '13 09:04

Andremoniy


2 Answers

You must assign volatile variables to local fields if you plan on doing any sort of multi-step logic (assuming of course, that the field is mutable).

for instance:

volatile String _field;

public int getFieldLength() {
  String tmp = _field;
  if(tmp != null) {
    return tmp.length();
  }
  return 0;
}

if you did not use a local copy of _field, then the value could change between the "if" test and the "length()" method call, potentially resulting in an NPE.

this is besides the obvious benefit of a speed improvement by not doing more than one volatile read.

like image 190
jtahlborn Avatar answered Oct 12 '22 11:10

jtahlborn


There are two sides of a coin.

On the one hand assignment to a volatile works like a memory barrier and it's very unlikely that JIT will reorder assignment with computeFieldValue invocation.

On the other hand in theory this code breaks JMM. Because for some reasons some JVM is allowed to reorder computeFieldValue with assignment and you see partially initialized object. This is possible as long as variable read is not order with variable write.

field = result = computeFieldValue();  

does not happen before

if (result == null) { // First check (no locking) 

As long as java code supposed to be "write once run everywhere" DCL is a bad practice and should be avoided. This code is broken and is not a point of consideration.

If you have multiple reads of a volatile variable in a method, by assigning it to a local variable first you minimize such reads, which are more expensive. But I don't think, that you get a performance boost. This is likely to be a theoretical improvement. Such optimization should be left to JIT and is not a point of developer's considerations. I agree with this.

like image 24
Mikhail Avatar answered Oct 12 '22 11:10

Mikhail