Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

145
Vistas
Is it guaranteed that volatile field would be properly initialized

Here:

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

Are the same guarantees held for the volatile field? What if the y field in the following example would be volatile could we observe 0?

class FinalFieldExample { 
final int x;
int y; 
static FinalFieldExample f;

public FinalFieldExample() {
    x = 3; 
    y = 4; 
} 

static void writer() {
    f = new FinalFieldExample();
} 

static void reader() {
    if (f != null) {
        int i = f.x;  // guaranteed to see 3  
        int j = f.y;  // could see 0
    } 
} 

}

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

I think reading 0 is possible.

The spec says:

A write to a volatile variable v synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).

In our case, we have a write and a read of the same variable, but there is nothing that ensures the read to be subsequent. In particular, the write and read occur in different threads that are not related by any other synchronization action.

That is, it is possible that the read will occur before the write in synchronization order.

This may sound surprising given that the writing thread writes f after y, and the reading thread reads y only if it detects f has been written. But since the write and read to f are not synchronized, the following quote applies:

More specifically, if two actions share a happens-before relationship, they do not necessarily have to appear to have happened in that order to any code with which they do not share a happens-before relationship. Writes in one thread that are in a data race with reads in another thread may, for example, appear to occur out of order to those reads.

The explanatory notes to example 17.4.1 also reaffirm that the runtime is permitted to reorder these writes:

If some execution exhibited this behavior, then we would know that instruction 4 came before instruction 1, which came before instruction 2, which came before instruction 3, which came before instruction 4. This is, on the face of it, absurd.

However, compilers are allowed to reorder the instructions in either thread, when this does not affect the execution of that thread in isolation.

In our case, the behavior of the writing thread, in isolation, is not affected by reordering the writes to f and y.

over 4 years ago · Santiago Trujillo Denunciar

0

Yes, it is possible to see 0 when

class FinalFieldExample { 
  final int x;
  volatile int y;
  static FinalFieldExample f;
  ...
}

The short explanation:

  • writer() thread publishes f = new FinalFieldExample() object via a data race
  • because of this data race, reader() thread is allowed see f = new FinalFieldExample() object as semi-initialized.
    In particular, reader() thread can see a value of y that was before y = 4; — i.e. initial value 0.

More detailed explanations are here.

You can reproduce this behavior on ARM64 with this jcstress test.

over 4 years ago · Santiago Trujillo Denunciar

0

Yes, 0 is possible when x is volatile, because there is no guarantee that the write x = 3 in the writer() thread always happens-before the read local_f.x in the reader() thread.

class FinalFieldExample { 
  volatile int x;
  static FinalFieldExample f;

  public FinalFieldExample() {
    x = 3;
  }

  static void writer() {
    f = new FinalFieldExample();
  }

  static void reader() {
    var local_f = f;
    if (local_f != null) {
        int i = local_f.x;  // could see 0
    }
  }
}

As a result, even though x is volatile (which means that all reads and writes to x happen in a global order), nothing prevents the read local_f.x in the reader() thread from happening before the write x = 3 in the writer() thread.
local_f.x in these case will return 0 (the default value for int, which works like an initial write).

The problem is that after the reader() thread reads f, there is no guarantee (i.e. no happens-before relation) that it sees the inner state on f correctly: i.e. it may not see the write x = 3 into the inner field f.x made by the writer() thread in FinalFieldExample constructor.

You can create this happens-before relation by:

  • either making f volatile (x can be made non-volatile)
    class FinalFieldExample { 
      int x;
      static volatile FinalFieldExample f;
      ...
    }
    
    From the JLS:

    A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

  • or making x final instead of volatile
    class FinalFieldExample { 
      final int x;
      static FinalFieldExample f;
      ...
    }
    
    From the JLS:

    An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda