Sicurezza dei Thread nelle Classi Singleton di Java

Il Singleton è uno dei pattern di progettazione creazionali più ampiamente utilizzati per limitare l’oggetto creato dalle applicazioni. Se lo stai utilizzando in un ambiente multi-threaded, allora la sicurezza del thread della classe singleton è molto importante. Nelle applicazioni del mondo reale, risorse come le connessioni al database o i Sistemi Informativi Aziendali (EIS) sono limitate e dovrebbero essere utilizzate saggiamente per evitare problemi di risorse. Per raggiungere questo obiettivo, possiamo implementare un pattern di progettazione Singleton. Possiamo creare una classe wrapper per la risorsa e limitare il numero di oggetti creati a runtime a uno.

Singleton Thread Safe in Java

In generale, seguiamo i seguenti passaggi per creare una classe singleton:

  1. Crea il costruttore privato per evitare la creazione di nuovi oggetti con l’operatore new.
  2. Dichiara un’istanza statica privata della stessa classe.
  3. Fornisci un metodo pubblico statico che restituirà la variabile di istanza della classe singleton. Se la variabile non è inizializzata, inizializzala; altrimenti, restituisci semplicemente la variabile di istanza.

Utilizzando i passaggi sopra indicati, ho creato una classe singleton che appare come segue. ASingleton.java

package com.journaldev.designpatterns;

public class ASingleton {

	private static ASingleton instance = null;

	private ASingleton() {
	}

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

}

Nel codice sopra, il metodo getInstance() non è thread-safe. Più thread possono accedervi contemporaneamente. Per i primi thread, quando la variabile di istanza non è inizializzata, possono entrare nel ciclo if e creare più istanze. Questo violerebbe la nostra implementazione singleton.

Come garantire la sicurezza dei thread in una classe Singleton?

Esistono tre modi per garantire la sicurezza dei thread.

  1. Creare la variabile di istanza al momento del caricamento della classe.
    Vantaggi:
  • Sicurezza dei thread senza sincronizzazione
  • Facile da implementare

Svantaggi:

  • Creazione anticipata di risorse che potrebbero non essere utilizzate nell’applicazione.
  • L’applicazione client non può passare alcun argomento, quindi non possiamo riutilizzarla. Ad esempio, avere una classe singleton generica per la connessione al database in cui l’applicazione client fornisce le proprietà del server del database.
  1. Sincronizzare il metodo getInstance().
    Vantaggi:
  • La sicurezza del thread è garantita.
  • L’applicazione client può passare parametri
  • L’inizializzazione ritardata è stata ottenuta

Contro:

  • Prestazioni lente a causa dell’overhead di blocco.
  • Sincronizzazione non necessaria che non è richiesta una volta che la variabile di istanza è inizializzata.
  1. Utilizzare il blocco sincronizzato all’interno del ciclo if e la variabile volatile
    Pro:
  • La sicurezza del thread è garantita
  • L’applicazione client può passare argomenti
  • L’inizializzazione ritardata è stata ottenuta
  • L’overhead di sincronizzazione è minimo e si applica solo per i primi thread quando la variabile è nulla.

Contro:

  • Condizione if aggiuntiva

Osservando tutti e tre i modi per ottenere la sicurezza del thread, penso che il terzo sia la migliore opzione. In tal caso, la classe modificata sarà simile a questa:

package com.journaldev.designpatterns;

public class ASingleton {

	private static volatile ASingleton instance;
	private static Object mutex = new Object();

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		ASingleton result = instance;
		if (result == null) {
			synchronized (mutex) {
				result = instance;
				if (result == null)
					instance = result = new ASingleton();
			}
		}
		return result;
	}

}

La variabile locale result sembra superflua. Ma è presente per migliorare le prestazioni del nostro codice. Nei casi in cui l’istanza è già inizializzata (la maggior parte delle volte), il campo volatile viene accesso solo una volta (a causa di “return result;” invece di “return instance;”). Ciò può migliorare le prestazioni complessive del metodo fino al 25 percento. Se pensi che ci siano modi migliori per ottenere questo o se la sicurezza del thread è compromessa nell’implementazione sopra, commenta e condividilo con tutti noi.

Suggerimento Bonus

Stringa non è un candidato molto adatto per essere utilizzato con la parola chiave synchronized. È perché sono memorizzati in un pool di stringhe e non vogliamo bloccare una stringa che potrebbe essere utilizzata da un altro pezzo di codice. Quindi sto usando una variabile Object. Per saperne di più sulla sincronizzazione e sulla sicurezza dei thread in Java.

Puoi controllare più esempi Java dal nostro Repository GitHub.

Source:
https://www.digitalocean.com/community/tutorials/thread-safety-in-java-singleton-classes