English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Questo articolo spiega l'esempio di modello di design singleton nel programming Android. Condividiamo con tutti per riferimento, come segue:
Uno, Introduzione
Il modello singleton è uno dei modelli più ampiamente utilizzati, potrebbe anche essere l'unico modello di design che molti ingegneri junior utilizzano. Quando si utilizza questo modello, la classe dell'oggetto singleton deve garantire che esista solo un'istanza. Molte volte, l'intero sistema ha bisogno di avere un oggetto globale, il che è utile per coordinare il comportamento complessivo del sistema.
二、Definizione
Assicurare che un certo tipo di classe abbia un solo esempio, e si auto-inizializza e fornisce questo esempio all'intero sistema.
三、Scenari di utilizzo
Assicurare che un certo tipo di classe abbia un solo oggetto, evitando di generare più oggetti che consumano troppe risorse, o che un tipo di oggetto dovrebbe avere solo un singolo esempio. Ad esempio, creare un oggetto che richiede molte risorse, come l'accesso a risorse di IO e database, in questo caso, è necessario considerare l'uso del modello singleton.
四、Metodi di implementazione
1、Modello di esecuzione di fame
Esempio di codice:
/** * Modello di esecuzione di fame */ public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
Vantaggi:Caricamento differito (caricare solo quando necessario)
Svantaggi:Non sicuro per thread, è facile verificarsi in condizioni di disallineamento in presenza di operazioni di lettura e scrittura frequenti su oggetti di database.
2、Modello di esecuzione affamata
Esempio di codice:
/** * Modello di esecuzione affamata */ public class Singleton { private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance() if(instance == null){ instance = new Singleton(); } return instance; } }
Confronto con il modello di esecuzione affamata, la keyword synchronized è stata aggiunta nel metodo getInstance(), il che significa che getInstance() è un metodo sincronizzato. Questo garantisce l'unicità dell'oggetto singleton in presenza di thread multipli. Ma riflettendo attentamente, potresti notare un problema: anche se l'istanza è stata inizializzata (l'istanza viene inizializzata la prima volta che viene chiamato), ogni chiamata al metodo getInstance() richiede la sincronizzazione, il che consuma risorse inutili. Questo è anche il problema più grande del modello di esecuzione affamata.
Vantaggi:Risolve il problema di sicurezza della thread.
Svantaggi:È necessario procedere con la creazione dell'istanza al momento del primo caricamento, con una reazione leggermente lenta, il problema più grande è che ogni chiamata a getInstance provoca una sincronizzazione, causando una sovraccarico di sincronizzazione non necessaria.
Supplemento:In Android, i metodi singleton utilizzati nei sorgenti sono InputMethodManager, AccessibilityManager e altri, che utilizzano questo modello di singleton
3、Controlllo di blocco in doppio controllo (DCL)
Esempio di codice:
/** Modello di singleton con controlllo的双重检查锁定(DCL) */ public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
La peculiarità di questo programma è naturalmente nel metodo getInstance, dove si può vedere che il metodo getInstance esegue due giudizi di vuoto su instance: il primo livello di giudizio è principalmente per evitare同步 non necessario, il secondo livello di giudizio è per creare l'istanza in caso di null.
Supponiamo che la thread A esegua la frase instance = new Singleton(), che sembra essere una singola frase di codice, ma in realtà non lo è. Questa frase di codice viene infine compilata in più istruzioni assembly, che roughly fanno tre cose:
(1) Assegnare una memoria per un'istanza di Singleton;
(2) Chiamare il costruttore di Singleton() per inizializzare i campi membri;
(3) Indicare l'oggetto instance verso lo spazio di memoria assegnato (in questo momento instance non è più null).
Ma, a causa della capacità del compilatore Java di eseguire in modo disordinato il processore, nonché delle regole di ordine di scrittura di Cache, registro e memoria principale stabilite nel modello di memoria Java (JMM) prima della JDK1.5, l'ordine delle due e delle tre frasi superiori non può essere garantito. Questo significa che l'ordine di esecuzione potrebbe essere 1-2-3 o 1-3-2. Se è quest'ultimo, se il passo 3 è stato completato e il passo 2 non è stato eseguito prima di essere switchato alla thread B, allora instance, poiché ha già eseguito il terzo punto nella thread A, è già non vuoto. Pertanto, la thread B prende direttamente instance, e quando lo utilizza, si verifica un errore. Questo è il problema di inefficacia del DCL, e questo errore difficile da tracciare e riprodurre potrebbe rimanere nascosto per molto tempo.
Dopo JDK 1.5, la SUN ha notato questo problema, ha regolato il JVM e ha specificato la parola chiave volatile, quindi se JDK è 1.5 o successivo, è sufficiente modificare la definizione di instance in private volatile static Singleton instance per garantire che l'oggetto instance venga letto ogni volta dalla memoria principale, così da poter utilizzare la scrittura DCL per completare il modello Singleton. Naturalmente, la parola chiave volatile può influenzare leggermente le prestazioni, ma considerando la correttezza del programma, sacrificare queste prestazioni è ancora ragionevole.
Vantaggi: Utilizzo efficiente delle risorse, l'oggetto Singleton viene istanziato solo quando viene eseguito getInstance per la prima volta, efficiente. In un ambiente con bassa concorrenza e bassa sicurezza, il modello Singleton potrebbe funzionare perfettamente
Svantaggi: La reazione è leggermente lenta durante il primo caricamento, e a volte può fallire anche a causa del modello di memoria Java. In un ambiente ad alta concorrenza ci sono anche alcuni difetti, anche se la probabilità è molto bassa.
Supplemento: Nel progetto open-source di immagini per Android Android-Universal-Image-Loader (https://github.com/nostra13/Android-Universal-Image-Loader) Viene utilizzato questo metodo.
Il modello DCL è il modo di implementazione Singleton più utilizzato, è in grado di istanziare l'oggetto Singleton solo quando necessario e può garantire l'unicità dell'oggetto Singleton in quasi tutti i casi, a meno che il tuo codice non sia in un ambiente concorrente complesso o con versioni di JDK inferiori alla 6. Altrimenti, questo metodo dovrebbe essere sufficiente per soddisfare le tue esigenze.
4. Modello Singleton di classe interna statica
DCL, sebbene in qualche modo risolva problemi come il consumo di risorse, la sincronizzazione inutile e la sicurezza dei thread, tuttavia, in alcune circostanze può fallire. Questo problema è noto come fallimento del locking a doppia verifica (DCL), e viene trattato nell'ultimo capitolo del libro 'Pratiche di programmazione concorrente in Java', dove si sottolinea che questa 'ottimizzazione' è brutta e non viene raccomandata. Invece, si suggerisce di sostituire il seguente codice:
Esempio di codice:
/** * Modello Singleton di classe interna statica */ public class Singleton { private Singleton(){} public static Singleton getInstance(){ return SingletonHolder.instance; } /** * Classe interna statica * Carica in ritardo, riduce i costi della memoria */ private static class SingletonHolder{ private static final Singleton instance = new Singleton(); } }
Quando il Singleton viene caricato per la prima volta, l'istanza instance non viene inizializzata, l'istanza viene inizializzata solo quando viene chiamato il metodo getInstance di Singleton per la prima volta. Pertanto, la prima chiamata al metodo getInstance carica la classe SingletonHolder, questo metodo non solo garantisce la sicurezza thread, ma anche l'unicità dell'oggetto singleton, e differisce anche l'istanziazione del singleton, quindi è il modo di implementazione del modello singleton raccomandato.
Vantaggi: carico differito, thread-safe (in Java il caricamento delle classi è mutex), e riduce anche i consumi di memoria
5. Singleton enum
Sono stati illustrati alcuni modi di implementazione del modello singleton, ma questi modi di implementazione sono piuttosto complicati o possono presentare problemi in alcune situazioni.
Esempio di codice:
/** * Modello singleton enum */ public enum Singleton { /** * 1. Supportato da Java 1.5; * 2. Fornisce un meccanismo di serializzazione senza costi; * 3. Previene l'istanziazione multipla in presenza di attacchi serializzati o riflettivi complessi; */ instance; private String others; Singleton() { } public String getOthers() { return others; } public void setOthers(String others) { this.others = others; } }
La semplicità di scrittura è il maggiore vantaggio dell'enumerazione singleton, l'enumerazione in Java è uguale a una classe comune, può avere campi e anche i propri metodi. Più importante ancora, la creazione predefinita dell'istanza enum è thread-safe e in ogni caso è un singleton.
Perché dico questo? Nei vari modi di implementazione del singleton elencati sopra, ci sono alcune situazioni in cui possono essere ri-generati gli oggetti, ossia la deserializzazione.
La serializzazione può scrivere un'istanza dell'oggetto singleton su disco e poi leggerla indietro, ottenendo così efficacemente un'istanza. Anche se il costruttore è privato, durante la deserializzazione è possibile creare un nuovo istanza della classe tramite un metodo speciale, il che equivale a chiamare il costruttore della classe. L'operazione di deserializzazione fornisce una funzione di accrocchio speciale, la classe ha un metodo privato, instanziato, readResolve(), che permette ai sviluppatori di controllare la deserializzazione dell'oggetto. Ad esempio, se si desidera prevenire che l'istanza singleton venga ri-generata durante la deserializzazione, è necessario aggiungere il seguente metodo:
private Object readResolve() throws ObjectStreamException {}} return instance; }
Ossia restituire l'oggetto instance nel metodo readResolve, invece di generare un nuovo oggetto per default. Per gli enum, non esiste questo problema perché non viene generata una nuova istanza durante la deserializzazione.
VantaggiFornisce meccanismi di serializzazione gratuiti, prevenendo l'istanziazione multipla in presenza di attacchi di serializzazione o reflection, anche in presenza di serializzazione complessa.
SvantaggiDalla versione Java 1.5.
L'argomento principale trattato è di come creare 5 metodi di singleton, ognuno dei quali può essere utilizzato in base ai suoi pro e contro nel progetto personale.
Chi è interessato a ulteriori contenuti relativi a Android può consultare le sezioni speciali di questo sito: 'Guida di introduzione e avanzamento dello sviluppo Android', 'Trucchi di debug e soluzioni ai problemi comuni di Android', 'Sommarizzazione dell'uso dei componenti di base di Android', 'Sommarizzazione delle tecniche di vista View di Android', 'Sommarizzazione delle tecniche di layout di Android' e 'Sommarizzazione dell'uso dei controlli di Android'.
Spero che il contenuto di questo articolo possa essere utile per la progettazione di applicazioni Android.
Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, è di proprietà del rispettivo autore, il contenuto è stato contribuito volontariamente dagli utenti di Internet e caricato autonomamente, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.