Pregunta

Me debe estar haciendo algo muy tonto, pero me estoy poniendo un ExceptionInInitializerError cuando intento crear una instancia de un objeto en mi Singleton:

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  // Do I instantiate obj here???
  private MySingleton() {
    //obj = new OtherObject();
  }

  // Or here?
  {
    //obj = new OtherObject();
  }

  // Or where? ...

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

¿Debo hacer el otro objeto en el constructor, o es que siempre se supone que estar vacío para hijos únicos? Me da la excepción en tanto el constructor y el bloque de inicialización ...

Este es el principal ():

public static void main(String[] args) {
    try {
        MySingleton singleton = MySingleton.getInstance();
    } catch (Error e) {
        System.err.println("Error!");
    }
}
¿Fue útil?

Solución

estático secciones de inicialización para inicializar son miembros de la clase estática marcada. Desde OtherObject obj no es estático no debe ser inicializado allí. El lugar correcto es inicializar en el constructor.

Si usted está recibiendo un ExceptionInInitializerError cuando se tiene obj = new OtherObject() en el constructor, el problema puede estar en otra clase (OtherObject tal vez?) Que está inicializando incorrectamente miembros estáticos.

Otros consejos

Se puede evitar algunos de su confusión al eliminar el riesgo de inicialización perezosa (que eres Actualmente el pago de la excepción). Puesto que usted está realmente sólo la devolución de su instancia estática, ¿por qué no crear esa instancia estática en tiempo de ejecución (es decir, no espere a null):

class MySingleton {

  private static MySingleton instance = new MySingleton();

  // You could do this here or in the constructor
  // private OtherObject obj = new OtherObject();

  /** Use this if you want to do it in the constructor instead. */
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  /** Now you can just return your static reference */
  public static MySingleton getInstance() {
      return instance;
  }

}

Si se fijan, ahora todo es determinista y directo. Su MySingleton.instance se rellena en tiempo de ejecución y se accede a través de la MySingleton.getInstance() método estático.

Me doy cuenta de que esto no coincide con el patrón exacto del original de libro GOF patrones de diseño, sino que dará cuenta de que el uso de la clase es efectivamente el mismo.

Editar : el seguimiento de algunos de los puntos de seguridad hilo planteadas en otras respuestas y comentarios, voy a tratar de ilustrar cómo la solución propuesta original en la pregunta y en el libro GOF es No seguro para subprocesos. Para una mejor referencia, véase Java concurrencia en Prácticas que me poseer y tener en mi ACM / biblioteca en línea Safari. Es francamente una fuente mejor que mi ejemplo dibujado pero, bueno, pero podemos luchar ....

Así, imaginemos que tenemos dos hilos nombrados Thread1 y Thread2 y, casualmente, cada uno golpea el método MySingleton.getInstance () en el mismo momento. Esto es totalmente posible en un sistema de múltiples núcleos hyperthreaded moderna. Ahora, a pesar de que estos dos temas pasaron a golpear el punto de entrada de este método, al mismo tiempo, no hay ninguna garantía de que se va a golpear ninguna declaración particular. Por lo tanto, se podía ver algo como esto:

// Note that instance == null as we've never called the lazy getInstance() before.

Thread1: if (instance == null)
Thread2: if (instance == null) // both tests pass - DANGER
Thread1:     instance = new MySingleton();
Thread2:     instance = new MySingleton(); // Note - you just called the constructor twice
Thread1: return instance; // Two singletons were actually created 
Thread2: return instance; // Any side-effects in the constructor were called twice

El problema se ilustra en la prueba si es nulo se llama carrera condición . No se puede saber quién va a lo comunicado cuándo. Como resultado, es como si ambos hilos están compitiendo entre sí para un acantilado.

Si nos fijamos en el mismo tipo de examen de mi ejemplo, con los dos hilos todavía golpear getInstance () en el mismo momento, se ve algo como esto:

Thread1: return instance;
Thread2: return instance;

simplista, sí, pero ese es mi punto. El objeto se construyó una vez, hace mucho tiempo, y los hilos puede contar con su valor de ser coherente. No existe ninguna carrera.

NOTA: usted todavía tiene que preocuparse por el contenido del constructor para OtherObject. La lección que hay: la concurrencia es difícil. Si usted está haciendo su seguro para hilos constructor (que debería), asegúrese de que el autor de OtherObject que está haciendo la misma cortesía.

La respuesta es simple, no utilice Singleton. Mientras que el libro GoF tiene algunas buenas ideas, el patrón Singleton no es uno de ellos.

Como otros han dicho upthread, el hilo uso seguro adecuado de singletons es difícil, ver

de seguro para hilos únicos

En realidad, todos los implementos de un Singleton es un objeto global. Esto es malo, contamina el espacio de nombres. Hace que las pruebas adecuadas unidad (Junit, etc.) mucho más difícil, si no imposible. Usted no lo necesita, nunca. Una clase de fábrica sencilla estática es un código más limpio, evita la contaminación global y es menos código.

se debe crear una instancia OtherObj en su constructor. ¿Cuál es el código exacto que está dando el error?

editar - A continuación trabajó para mí

class MySingleton {

  private static MySingleton instance = null;
  private Integer obj;


  private MySingleton() {
    obj = new Integer(2);
  }


  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

y luego simplemente llame getInstance de un bucle principal. Es posible que desee mirar a

http://en.wikipedia.org/wiki/Singleton_pattern#Java

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
      obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

Su clase Singleton no tiene la culpa aquí. Yo diría que un problema en el contructor de la clase OtherObject.

Una sintaxis correcta sería:

class MySingleton {

  private static MySingleton instance = null;
  private OtherObject obj;

  private MySingleton() {
    obj = new OtherObject();
  }

  public static MySingleton getInstance() {
    if (instance == null)
      instance = new MySingleton();
    return instance;
  }

}

Ahora, sólo tiene que darnos más información sobre el OtherObject: -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top