
Cos'è un singleton in Java?
Singleton è uno dei modelli di progettazione a livello di classe più semplici. A volte le persone dicono "questa classe è singleton", il che significa che la classe implementa il modello di progettazione singleton. A volte è necessario scrivere una classe in cui limitiamo l'istanza a un singolo oggetto. Ad esempio, una classe responsabile della registrazione o della connessione a un database.Il modello di progettazione singleton descrive come possiamo raggiungere questo obiettivo.Un singleton è un modello di progettazione che fa due cose:-
Garantisce che ci sarà sempre e solo un'istanza della classe.
-
Fornisce un unico punto di accesso globale a tale istanza.
-
Un costruttore privato. Ciò limita la possibilità di creare oggetti della classe al di fuori della classe stessa.
-
Un metodo statico pubblico che restituisce l'istanza della classe. Questo metodo è chiamato getInstance . Questo è il punto di accesso globale all'istanza della classe.
Opzioni di implementazione
Il modello di progettazione singleton viene applicato in vari modi. Ogni opzione è buona e cattiva a modo suo. Come sempre, non esiste un'opzione perfetta qui, ma dovremmo sforzarci di trovarne una. Prima di tutto, decidiamo cosa costituisce buono e cattivo e quali metriche influenzano il modo in cui valutiamo le varie implementazioni del modello di progettazione. Iniziamo con il bene. Ecco i fattori che rendono un'implementazione più succosa e accattivante:-
Inizializzazione lazy: l'istanza non viene creata finché non è necessaria.
-
Codice semplice e trasparente: questa metrica, ovviamente, è soggettiva, ma è importante.
-
Thread safety: funzionamento corretto in un ambiente multi-thread.
-
Prestazioni elevate in un ambiente multi-thread: blocco dei thread minimo o nullo durante la condivisione di una risorsa.
-
Nessuna inizializzazione pigra: quando la classe viene caricata all'avvio dell'applicazione, indipendentemente dal fatto che sia necessaria o meno (paradossalmente, nel mondo IT è meglio essere pigri)
-
Codice complesso e di difficile lettura. Anche questa metrica è soggettiva. Se i tuoi occhi iniziano a sanguinare, supponiamo che l'implementazione non sia la migliore.
-
Mancanza di sicurezza del filo. In altre parole, "pericolo filo". Operazione errata in un ambiente multi-thread.
-
Scarse prestazioni in un ambiente multi-thread: i thread si bloccano a vicenda sempre o spesso quando condividono una risorsa.
Codice
Ora siamo pronti a considerare varie opzioni di implementazione e indicare i pro e i contro:Semplice
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
L'implementazione più semplice. Professionisti:
-
Codice semplice e trasparente
-
Sicurezza del filo
-
Prestazioni elevate in un ambiente multi-thread
- Nessuna inizializzazione pigra.
Inizializzazione pigra
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Professionisti:
-
Inizializzazione pigra.
-
Non thread-safe
Accesso sincronizzato
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Professionisti:
-
Inizializzazione pigra.
-
Sicurezza del filo
-
Scarse prestazioni multithread
Chiusura a doppio controllo
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Professionisti:
-
Inizializzazione pigra.
-
Sicurezza del filo
-
Prestazioni elevate in un ambiente multi-thread
-
Non supportato nelle versioni precedenti di Java precedenti alla 1.5 (l'utilizzo della parola chiave volatile è stato risolto dalla versione 1.5)
Titolare di classe
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Professionisti:
-
Inizializzazione pigra.
-
Sicurezza del filo.
-
Prestazioni elevate in un ambiente multi-thread.
-
Il corretto funzionamento richiede la garanzia che l' oggetto singleton sia inizializzato senza errori. In caso contrario, la prima chiamata al metodo getInstance risulterà in un ExceptionInInitializerError e tutte le chiamate successive produrranno un NoClassDefFoundError .
Implementazione | Inizializzazione pigra | Sicurezza del filo | Prestazioni multithread | Quando usare? |
---|---|---|---|---|
Semplice | - | + | Veloce | Mai. O forse quando l'inizializzazione pigra non è importante. Ma non sarebbe mai stato meglio. |
Inizializzazione pigra | + | - | Non applicabile | Sempre quando il multithreading non è necessario |
Accesso sincronizzato | + | + | Lento | Mai. O forse quando le prestazioni multithread non contano. Ma non sarebbe mai stato meglio. |
Chiusura a doppio controllo | + | + | Veloce | In rari casi in cui è necessario gestire le eccezioni durante la creazione del singleton (quando il singleton titolare della classe non è applicabile) |
Titolare di classe | + | + | Veloce | Ogni volta che è necessario il multithreading ed è garantito che l'oggetto singleton verrà creato senza problemi. |
Pro e contro del pattern singleton
In generale, un singleton fa esattamente ciò che ci si aspetta da esso:-
Garantisce che ci sarà sempre e solo un'istanza della classe.
-
Fornisce un unico punto di accesso globale a tale istanza.
-
Un singleton viola il principio di responsabilità singola: oltre ai suoi doveri diretti, la classe singleton controlla anche il numero di istanze.
-
La dipendenza di una classe ordinaria da un singleton non è visibile nel contratto pubblico della classe.
-
Le variabili globali sono cattive. Alla fine, un singleton si trasforma in una pesante variabile globale.
-
La presenza di un singleton riduce la testabilità dell'applicazione nel suo complesso e delle classi che utilizzano il singleton in particolare.
GO TO FULL VERSION