Ciclo infinito con un singleton: questo tipo di problema ha un nome?

4

Ho riscontrato un errore insolito mentre lavoravo al mio progetto. Per imparare meglio e ricordarlo, vorrei sapere se questo tipo di errore ha un nome o una definizione. (L'errore stesso OutOfMemoryError non è insolito, sto parlando di ciò che ha portato a questo errore).

La mia situazione (semplificata) era questa:

Ho avuto una classe Singleton :

class Singleton extends ClassA{
    private static Singleton instance;

    private Singleton(){ // implicitly calls super() }

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

Ed è superclasse ClassA :

abstract class ClassA{
    public ClassA(){
        ClassB objectB = new ClassB();
        // .. some logic ..
    }
}

E una classe ClassB che utilizza Singleton nel suo costruttore:

class ClassB{
    public ClassB(){
        Singleton singleton = Singleton.getInstance();
        // .. some logic ..
    }
}

Quello che succede è il seguente:

1- ClassB è istanziato da qualche parte. Il costruttore viene richiamato e chiama Singleton.getInstance() .

2- Singleton.getInstance() vede che instance == null ed esegue instance = new Singleton() .

3- Viene eseguito il costruttore di Singleton . È vuoto, ma chiama implicitamente il costruttore della superclasse ( ClassA ).

4- La superclasse di Singleton istanzia un ClassB oggetto new ClassB() .

Viene richiamato il costruttore di 5 ClassB e chiama Singleton.getInstance() ...

Poiché l'istanziazione di instance in Singleton non ha mai raggiunto la fine, instance == null restituisce ancora true e il ciclo non termina mai.

Risultante in un ciclo infinito, che alla fine ha generato un OutOfMemoryError .

Quindi la mia domanda è: questo tipo di errore di loop infinito con singleton è un problema comune? Qualche idea su come posso evitarlo in futuro?

    
posta Aviv Cohn 03.06.2014 - 20:02
fonte

3 risposte

7

È una semplice dipendenza circolare durante l'inizializzazione, indipendente da Singleton. Ci sono tre classi che si istanziano l'un l'altro in un ciclo: A istanzia B, che istanzia C, che a sua volta istanzia di nuovo A e tu hai un ciclo di istanza infinito.

Un'altra cosa che deve essere valutata è perché gli oggetti hanno una dipendenza circolare l'una dall'altra indipendentemente dall'istanza. Cioè, anche se in qualche modo sono stati tutti istanziati, non dovrebbero comunque avere una dipendenza circolare poiché questo è spesso indicativo di un alto accoppiamento e probabilmente altri problemi di progettazione.

Detto questo, sembra che Singleton non sia ancora completamente implementato, perché non garantisce singleton su più thread. Quando il codice di blocco necessario per l'implementazione di un singleton è codificato, si verificherà molto rapidamente in un deadlock.

Di solito, questi tipi di errori sono trovati:

  • In fase di progettazione esaminando le interazioni di classe,
  • Al momento dell'implementazione, tramite il codice in testa,
  • In fase di compilazione, poiché alcuni compilatori potrebbero rilevare ed emettere avvisi / errori,
  • In fase di runtime, ottenendo il tipo di eccezione generato da questo codice.
risposta data 22.06.2014 - 09:51
fonte
0

Posso pensare ad un paio di modi per interrompere il ciclo.

  1. Non istanziare un CMajor durante l'istanziazione di MusicalResources . Lascia che una funzione di livello superiore costruisca il Scale s necessario. Ogni volta che viene creato Scale , aggiungi un riferimento a MusicalResources .

  2. Non interrogare MusicalResources per Notes quando costruisci un'istanza di CMajor . Interrogali in base alle necessità.

risposta data 03.06.2014 - 22:14
fonte
0

Uno degli aspetti negativi di Singletons è il modo in cui interagiscono con le classi super e sub. Un altro lato negativo di Singletons li sta annidando - che diventa fastidioso. Senza offesa, ma trovo un po 'strano quando dici "Non vedo il problema ..." quando in effetti vedi un problema che fa scoppiare il tuo motore di runtime;)

A parte questo, il tuo modello è tutto kitty-wampus. Di nuovo, senza offesa, ma ...! Penso, ad esempio, che tu stia facendo un'equivalenza tra una scala e una nota che incasini la gerarchia. Prenderò prima il codice Singleton e poi fare un passo indietro e fare un diagramma delle relazioni is-a e has-a (ad esempio, potrebbe essere più pulito se Scale "ha una" Nota invece di "è una" Nota " )

Potrebbe essere utile schematizzarlo, con le classi, sottoclassi e istanze disposte con frecce tra di loro.

Se stai distribuendo oggetti di riferimento immutabili, raggrupparli come membri finali statici pubblici di alcune classi di contenitori è molto più pulito e meno incline di Singleton. Inoltre, non sono sicuro di dove, ma penso che anche le enumerie saranno tuoi amici qui.

(Le enumerazioni sono una specie della versione approvata da Java di Singleton immutabile, di nuovo senza la cattiveria.)

    
risposta data 03.06.2014 - 22:46
fonte

Leggi altre domande sui tag