2013-04-10 10 views
8

La parola chiave synchronize deve essere applicata a ciascun metodo di una classe che implementa il modello singleton come questo?Sincronizzazione Java in modalità singleton

public class Singleton { 

    private Singleton(){} 

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

     return instance; 
    } 

    public void DoA(){ 
    } 
} 

Poiché Singoletti non esporre un costruttore pubblico e il metodo getInstance() è sincronizzato, uno non necessità di sincronizzare metodo DOA e altri metodi pubblici esposte dalla classe Singleton.

Questo ragionamento è corretto?

+2

En sychronization generale dipende se si accede a dati condivisi nel metodo. – PeterMmm

+0

[Questo dovrebbe rispondere alla tua domanda] (http://stackoverflow.com/questions/777849/proper-usage-of-synchronized-singleton) – user1406177

+1

Io non la penso così, se getInstance è sincronizzato. ciò non significa che DoA sia sincronizzato. pure. –

risposta

16

È proprio come qualsiasi altra classe. Può o non può aver bisogno di ulteriore sincronizzazione.

consideri il seguente esempio:

public class Singleton { 

    private Singleton() {} 

    public synchronized static Singleton getInstance() { ... } 

    private int counter = 0; 

    public void addToCounter(int val) { 
    counter += val; 
    } 
} 

Se la classe deve essere utilizzato da più thread, addToCounter() ha una condizione di competizione. Un modo per risolvere il problema che è facendo addToCounter() sincronizzati:

public synchronized void addToCounter(int val) { 
    count += val; 
    } 

Ci sono altri modi per risolvere la condizione di competizione, per esempio utilizzando AtomicInteger:

private final AtomicInteger counter = new AtomicInteger(0); 

    public void addToCounter(int val) { 
    counter.addAndGet(val); 
    } 

Qui, abbiamo risolto la condizione di competizione senza usare synchronized.

+0

Come posso risolvere l'errore PMD "Usa il livello del blocco piuttosto che la sincronizzazione del livello del metodo" su getInstance? – rodi

+0

grazie per il suggerimento su "AtomicInteger". – asgs

9

Bene, lo scopo della classe Singleton è che al massimo esiste un'istanza e che tutti i thread possono accedere allo stesso oggetto.

Se non si desidera sincronizzare il metodo getInstance quanto segue potrebbe accadere

Thread1 entra getInstance()

Thread2 entra getInstance()

Thread1 valuta instance == null a true

Thread2 valuta instance == null a true

Thread1 assegna instance e restituisce

Thread2 re assegna instance = new Singleton() e ritorna.

Ora i thread hanno entrambi un'istanza di differenza della classe Singleton che è ciò che avrebbe dovuto essere impedito da questo modello.

La sincronizzazione impedisce che entrambi i thread possano accedere allo stesso blocco di codice allo stesso tempo. Quindi la sincronizzazione è necessaria in un ambiente con multithreading quando si istanziano classi singleton.

Ora, supponendo che più thread tenteranno di accedere ai metodi di Singletons allo stesso tempo, potrebbe essere necessaria la sincronizzazione anche su tali metodi. Soprattutto se cambiano i dati invece di leggerli solo questo è vero.

+0

Penso che la domanda si riferisca ai metodi pubblici dell'istanza Singleton e non alla statica 'getInstance'. – afsantos

+0

Sì, dovrei essere più paziente e leggere la domanda prima di rispondere. Espanderò la risposta ... – DeltaLima

1

Il modo corretto (Best in realtà) per utilizzare Singleton

private static singleton getInstance() { 
    if (minstance == null) { 
     synchronized (singleton.class) { 
      if (minstance == null) { 
       minstance = new singleton(); 
      } 
     } 
    } 
    return minstance; 
} 
+0

se 'minstance' sembra essere nullo, quindi sincronizzando il blocco con quell'istanza si otterrà' NullPointerException'. – asgs

+0

Sì. In realtà ho scritto il codice precedente in fretta. ;) – gaurav414u

+0

è una cattiva pratica - ha un doppio motivo di blocco controllato - e non funzionerà dopotutto - spiegazione qui http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html –

1

inizializzazione pigra e filo soluzione sicura:

public class Singleton { 

    public static class SingletonHolder { 
     public static final Singleton HOLDER_INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.HOLDER_INSTANCE; 
    } 
} 
Problemi correlati