Domanda

Perché il modello considerato rotto? Si guarda bene a me? Tutte le idee?

public static Singleton getInst() {
    if (instace == null) createInst();
    return instace;
}

private static synchronized createInst() {
     if (instace == null) {
         instace = new Singleton(); 
     }
}
È stato utile?

Soluzione

Si guarda bene a prima vista, ma questa tecnica ha molti problemi sottili e di solito dovrebbe essere evitato. Per esempio, si consideri la seguente sequenza di eventi:

  1. Discussione A nota che il valore è Non inizializzato, quindi si ottiene la bloccare e comincia a inizializzare il valore.
  2. Il codice generato dal compilatore è consentito aggiornare la variabile condivisa scegliere un parzialmente costruito oggetto prima di A ha terminato eseguendo l'inizializzazione.
  3. le comunicazioni thread B che l'ha condiviso variabile è stata inizializzata (o così sembra), e restituisce il suo valore. Poiché filo B ritiene che il valore è già inizializzato, non è così acquisire il blocco. Se B utilizza la oggetto prima che tutti i inizializzazione svolto da A viene visto da B il programma sarà probabilmente in crash.

Si potrebbe evitare questo utilizzando la parola chiave "volatile" per gestire le istanze Singleton correttamente

Altri suggerimenti

Tutta la discussione è un enorme, infinita spreco di tempo al cervello. 99,9% del tempo, single non abbiamo costi di installazione significative e non v'è alcun motivo per configurazioni in modo di ottenere non sincronizzato loading garantito-lazy.

Questo è come si scrive un Singleton in Java:

public class Singleton{
    private Singleton instance = new Singleton();
    private Singleton(){ ... }
    public Singleton getInstance(){ return instance; }
}

Meglio ancora, ne fanno un enum:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}

Non so se si è rotto, ma in realtà non è la soluzione più efficiente a causa di sincronizzazione, che è piuttosto costoso. Un approccio migliore sarebbe usare la 'titolare di inizializzazione On Demand Idiom', che carica il vostro Singleton in memoria la prima volta che è richiesto, come dice il nome, il caricamento in tal modo pigro. Il più grande vantaggio che si ottiene con questo idioma è che non è necessario per sincronizzare perché gli assicura JLS quella classe di carico è di serie.

voce di Wikipedia dettagliata sul tema: http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

Un'altra cosa da tenere a mente è che dal momento che sono emersi quadri iniezione di dipendenza come la primavera e Guice, istanze di classe vengono creati creati e gestiti da questi contenitori e vi fornirà un Singleton se lo si desidera, quindi non vale la pena rompendo la testa su di esso, a meno che non si vuole imparare a idea alla base del modello, che è utile. Si noti inoltre che i single forniti da questi contenitori CIO sono single per istanza contenitore, ma in genere avrete un contenitore CIO per ogni applicazione, in modo che non diventi un problema.

Il problema è il seguente: Il tuo JVM potrebbe riordinare il codice e campi non sono sempre le stesse per diversi thread. Date un'occhiata a questo: http://www.ibm.com/ developerWorks / java / library / j-dcl.html . L'utilizzo della parola chiave volatile dovrebbe risolvere questo problema, ma la sua rotta prima di Java 1.5.

La maggior parte del tempo sola controllata di chiusura è più che abbastanza veloce, provate questo:

// single checked locking: working implementation, but slower because it syncs all the time
public static synchronized Singleton getInst() {
    if (instance == null) 
        instance = new Singleton();
    return instance;
}

hanno anche uno sguardo a Java efficace, dove si trova un grande capitolo su questo argomento.

Per riassumere questo:. Non non ricontrollato blocco, ci sono idoms migliori

inizializzazione sul supporto della richiesta Idiom , yup il gioco è fatto:

public final class SingletonBean{

    public static SingletonBean getInstance(){
        return InstanceHolder.INSTANCE;
    }

    private SingletonBean(){}

    private static final class InstanceHolder{
        public static final SingletonBean INSTANCE = new SingletonBean();
    }

}

Anche se Joshua Bloch raccomanda inoltre l'Enum Singleton modello in Effective Java Capitolo 2, Articolo 3:

// Enum singleton - the prefered approach
public enum Elvis{
    INSTANCE;
    public void leaveTheBuilding(){ ... }
}

Questo non risponde alla tua domanda (gli altri hanno già fatto), ma voglio raccontarvi la mia esperienza con single / oggetti inizializzati pigri:

Abbiamo avuto un paio di singletons nel nostro codice. Una volta che abbiamo dovuto aggiungere un parametro del costruttore per un Singleton e aveva un problema serio, perché la costruzione di questo Singleton è stato invocato il getter. Ci seguivano solo le possibili soluzioni:

  • fornire un getter statico (o un altro singolo) per l'oggetto che è stato necessario per inizializzare il singleton,
  • passare l'oggetto per inizializzare il singleton come parametro per il getter o
  • sbarazzarsi del Singleton passando casi intorno.

Infine, l'ultima opzione era la strada da percorrere. Ora inizializziamo tutti gli oggetti a inizio applicazione e passare richiesto casi in tutto (forse come una piccola interfaccia). Non abbiamo rimpianto questa decisione, in quanto

  • le dipendenze di un pezzo di codice è cristallino,
  • possiamo testare il nostro codice molto più facile, fornendo implementazioni fittizie degli oggetti richiesti.

La maggior parte delle risposte qui sono corrette sul perché si è rotto, ma sono errate o suggerendo strategie discutibili per una soluzione.

Se davvero, davvero necessario utilizzare un Singleton (che nella maggior parte dei casi si non dovrebbe , in quanto distrugge verificabilità, la logica combina su come costruire una classe con il il comportamento della classe, cucciolate le classi che utilizzano il Singleton con la conoscenza di come ottenere uno, e porta a codice più fragile) e sono preoccupati per la sincronizzazione, la soluzione corretta è quella di utilizzare una statica inizializzatore per istanziare l'istanza.

private static Singleton instance = createInst();

public static Singleton getInst() {
    return instance ;
}

private static synchronized createInst() {
    return new Singleton(); 
}

I Java linguaggio di specifica garantisce che initiailzers statici verranno eseguiti solo una volta, quando una classe viene caricato per la prima volta, e in un modo thread-safe garantito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top