corretto utilizzo di Singleton sincronizzato?
-
13-09-2019 - |
Domanda
Così sto pensando di costruire un progetto hobby, una tantum genere di cose, giusto per rispolverare la mia programmazione / progettazione.
E 'fondamentalmente un multi threaded ragnatela, aggiornando la stessa struttura dati object-> int.
Quindi è sicuramente eccessivo di utilizzare un database per questo, e l'unica cosa che riuscivo a pensare è un Singleton thread-safe utilizzato per contenere la mia struttura dati. http : //web.archive.org/web/20121106190537/http: //www.ibm.com/developerworks/java/library/j-dcl/index.html
C'è un approccio diverso dovrei guardare per?
Soluzione
interblocco ricontrollato ha dimostrato di essere corretto e imperfetta (come almeno in Java). Fare una ricerca o guardare di Wikipedia per il motivo esatto.
In primo luogo è la correttezza del programma. Se il codice non è thread-safe (in un ambiente multi-threaded) allora è rotto. Correttezza viene prima l'ottimizzazione delle prestazioni.
Per essere corretta dovrete sincronizzare l'intero metodo getInstance
public static synchronized Singleton getInstance() {
if (instance==null) ...
}
o staticamente inizializzarlo
private static final Singleton INSTANCE = new Singleton();
Altri suggerimenti
Utilizzando l'inizializzazione pigra per il database in un web crawler non è probabilmente vale la pena. inizializzazione differita aggiunge complessità e un colpo di velocità in corso. Un caso in cui sia giustificato è quando c'è una buona probabilità non saranno mai necessari i dati. Inoltre, in un'applicazione interattiva, può essere utilizzato per ridurre il tempo di avvio e dare il illusione di velocità.
Per un'applicazione non interattiva come un web-crawler, che sarà sicuramente bisogno il suo database di esistere subito, l'inizializzazione pigra è una scelta povera.
D'altra parte, un web crawler è facilmente parallelizzabile, e beneficerà notevolmente da essere multi-thread. Usandolo come un esercizio di padroneggiare la libreria java.util.concurrent
sarebbe estremamente utile. In particolare, guarda ConcurrentHashMap
e < a href = "http://java.sun.com/javase/6/docs/api/java/util/concurrent/ConcurrentSkipListMap.html" rel = "noreferrer"> ConcurrentSkipListMap
, che consentirà a più thread leggere e aggiornare una mappa condivisa.
Quando si sbarazzarsi di inizializzazione differita, il più semplice pattern Singleton è qualcosa di simile:
class Singleton {
static final Singleton INSTANCE = new Singleton();
private Singleton() { }
...
}
Il final
parola chiave è la chiave qui. Anche se si fornisce un static
"getter" per il singleton piuttosto che permettere l'accesso campo diretto, rendendo il final
Singleton aiuta a garantire la correttezza e consente di ottimizzare più aggressiva dal compilatore JIT.
Se la vostra vita dipendesse da pochi microsecondi, allora vi consiglio di ottimizzare la risorsa di blocco a dove realmente importava.
Ma in questo caso la parola chiave qui è progetto hobby !
Il che significa che se si è sincronizzato l'intero getInstance () metodo che andrà bene nel 99,9% dei casi. Non voglio raccomandare di farlo in altro modo.
In seguito, se si prova per mezzo di profiling che il getInstance () La sincronizzazione è il collo di bottiglia del vostro progetto, allora si può andare avanti e ottimizzare la concorrenza. Ma ho davvero dubbi che causerà problemi.
Jeach!
Prova il Bill Pugh soluzione di inizializzazione sul supporto richiesta idioma. La soluzione è la più portabile su diversi compilatori Java e le macchine virtuali. La soluzione è thread-safe senza richiedere speciali costrutti di linguaggio (cioè volatile e / o sincronizzato).
http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
come Joshua Bloch sostiene nel suo libro "Effective Java 2 ° edizione" Ho anche d'accordo che un unico tipo di elemento enum è il modo migliore per attuare un Singleton.
public enum Singleton {
INSTANCE;
public void doSomething() { ... }
}
Se si guarda al fondo di questo articolo, vedrete il suggerimento di utilizzare solo un campo statico. Questa sarebbe la mia inclinazione: non ha realmente bisogno di un'istanza pigro (quindi non c'è bisogno getInstance()
essere sia una funzione di accesso e un metodo di fabbrica). Si vuole solo assicurarsi di avere una e una sola di queste cose. Se si ha realmente bisogno l'accesso globale a una cosa del genere, mi piacerebbe utilizzare che il codice di esempio verso il fondo :
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
Si noti che il Singleton è ora costruito durante l'installazione di campi statici. Questo dovrebbe funzionare e non affrontare i rischi di threading di potenzialmente cose mis-sincronizzazione.
Detto questo, forse quello che si ha realmente bisogno è una delle strutture di dati thread-safe disponibili nelle JDK moderni. Per esempio, io sono un grande fan della ConcurrentHashMap : (! FTW). filo di sicurezza più io non è necessario scrivere il codice
Perché non creare una struttura di dati che si passa ad ognuno dei fili come iniezione di dipendenza. In questo modo non è necessario un Singleton. Hai ancora bisogno di fare il thread-safe.
L'articolo si fa riferimento parla solo di rendere la creazione dell'oggetto Singleton, presumibilmente una collezione, in questo caso, thread-safe. È inoltre necessario una raccolta thread-safe in modo che le operazioni di raccolta anche lavorare come previsto. Assicurarsi che la raccolta degli elementi del Singleton è sincronizzato, magari utilizzando un ConcurrentHashMap .
Leggi questo articolo Attuazione del pattern Singleton in C #
public sealed class Singleton
{
Singleton()
{
}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
Come su:
public static Singleton getInstance() {
if (instance == null) {
synchronize(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}