2012-02-25 9 views

Respuesta

1

nuevo operador puede devolver un valor antes de que termine el constructor de la clase. Entonces una variable puede no leer nulo pero contiene una instancia de clase no inicializada. Esto sucede debido a la reordenación de bytes.

Algunas aclaraciones: Desde una perspectiva de subproceso único, la JVM puede reordenar algunas instrucciones. Al crear una instancia que tradicionalmente se podría pensar que es la siguiente:

  • asignar memoria
  • plazo de inicialización (constructor)
  • referencia asignar a var

Mientras que, de hecho, la JVM podría hacer algo como:

  • asignar memoria
  • Referencia
  • asignar a var
  • plazo de inicialización (constructor)

Esto tiene ventajas de rendimiento ya que las direcciones no tienen que ser las operaciones de búsqueda de nuevo. Desde una perspectiva de hilo único esto no cambia el orden de la lógica. Tu programa funciona bien. Pero esto plantea un problema en el código multiproceso. Esto significa que la referencia puede publicarse antes de que se ejecute el constructor. Por lo tanto, necesita una regla 'pasar antes' para asegurarse de que la instancia esté completamente inicializada. La declaración de variables volátiles obligará a las reglas anteriores.

Más sobre reordenamiento: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering

+0

Podría citar una fuente? – musiKk

+0

@musiKk buena pregunta, buscándola. –

+2

Hubiera pensado que, en lugar de esto, la referencia probablemente se trata de publicar el objeto dentro del constructor (o algo que llama). No puedo pensar en un caso en el que el nuevo operador devuelva una referencia de objeto antes de que se complete el constructor que se llama. – arcy

3

consideran este código:

public class World{ 
    public static Point _point; 

    public static void main(String[] args){ 
     new PointMaker().start(); 
     System.out.println(_point); 
    } 
} 

public class Point{ 
    private final int _x, _y; 

    public Point(int x, int y){ 
     _x = x; 
     World._point = this;//BAD: publish myself before I'm fully constructed 
     //some long computation here 
     _y = y; 
    } 

    public void toString(){ 
     return _x + "," + _y; 
    } 
} 

public class PointMaker extends Thread{ 
    public void run(){ 
     new Point(1, 1); 
    } 
} 

Debido Point publica en sí antes de ajustar el valor de _y, la llamada a println puede producir "1,0" en lugar de la "1,1" esperado.

(Tenga en cuenta que también puede producir si "null"PointMaker + Point.<init> no obtienen lo suficiente para establecer el campo World._point antes de la llamada a println ejecuta.)

+1

Para ser exactos, incluso puede imprimir "0,0". Si filtremos esta referencia del constructor, el JLS no ofrece garantías finales. – Voo

Cuestiones relacionadas