English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Design pattern Singleton in Java

Java - Design Pattern del Singleton

Prefazione:

Nel processo di sviluppo del software, spesso ci sono alcuni oggetti di cui abbiamo bisogno solo uno, come: threadpool (thread pool), cache (cache), finestra di dialogo, preferenze e così via. Questi oggetti, se si creano più istanze, possono causare alcuni problemi inutili, come comportamenti anormali del programma, utilizzo eccessivo delle risorse, ecc. In questo caso, il modello Singleton può garantire che una classe abbia solo una istanza e fornire un punto di accesso globale. Di seguito esploreremo come implementare il modello Singleton utilizzando un semplice esempio di classe Singleton.

/* 那么是否可以在使用延迟实例化的同时又不会造成线程不安全且增加访问效率呢?接下来就用双重检查加锁来改进一下。 */
 * La classe Singleton più classica
 */
public class Singleton {
  // Viene impostato come variabile statica per registrare l'istanza unica di Singleton
  private static Singleton singleInstance;
  private Singleton(){
    // Il metodo costruttore è dichiarato come privato, quindi può essere chiamato solo all'interno della classe Singleton
  }
  /*
   * Ottiene l'oggetto Singleton, se non è stato istanziato, istanzia un oggetto e restituisce questa istanza
   */
  public static Singleton getInstance(){
    if (singleInstance == null) {
      singleInstance = new Singleton();
    }
    return singleInstance;
  }
  return singletongA;
}

Dall'esempio sopra, si può vedere che la classe Singleton gestisce herself il processo di istanziazione di questa classe, e fornisce un punto di accesso globale, ovvero il metodo statico getInstance(), che restituisce un'istanza quando altre classi devono utilizzare Singleton. Questo modello Singleton ha un vantaggio, ovvero la延迟实例化, che in altre parole significa la延迟初始化, ovvero creare l'istanza solo quando la classe è necessaria, non creando un'istanza quando si carica la classe. Questo ha il vantaggio di evitare lo spreco di prestazioni. Ad esempio, alcuni oggetti non sono necessari all'inizio del programma, o non sono stati utilizzati durante l'esecuzione del programma. Tuttavia, questo esempio ha anche un difetto, ovvero la sicurezza della thread non è sufficiente. Poiché se più thread eseguono contemporaneamente il metodo getInstance() e l'istanza Singleton non è stata ancora new Singleton(), allora tutti i thread riterranno singleInstance come null e istanzieranno Singleton, causando così la creazione di più istanze Singleton, il che non corrisponde all'originale intenzione del modello Singleton. Quindi, il passo successivo potrebbe essere migliorare questo

public class SingletonA {
  private static SingletonA singletongA;
  private SingletonA(){
  }
  /*
   * Aggiunge la parola chiave synchronized per rendere il metodo getSingletonA sincronizzato
   */
  public static synchronized SingletonA getInstanceA(){
    if (singletongA == null) {
      singletongA = new SingletonA();
    }
    singletongA = new SingletonA();
  }
  return singletongA;
}

// 其他方法

从这个例子上看增加了synchronized可以使getInstanceA()变成一个同步的方法,这时线程在进入这个方法之前就需要等待其他线程离开这个方法才能进入,也就使得该方法只能同时存在一个线程在执行它。

可能差不多问题解决了,但是要知道同步方法是会影响程序执行效率的,在此例子中我们只是为了解决第一个例子中第一次执行getInstance()方法不会产生多个实例,而这个例子中却会导致每次需要实例时都会调用getInstanceA()同步方法,而在已经有实例之后的调用synchronized就会是累赘,因为我们已经无需担心这个单例类会再次被创建出新的实例。因此我们还需要做一下改进。

既然上面说到延迟实例化,那么如果是不用的话那就简单多了。
  public class SingletonB {
  // 在静态初始化器(static initializen)中创建单例,保证线程安全
  private static SingletonB singletonB = new SingletonB();
    private SingletonB(){
  }
  // 构造函数
    public static SingletonB getInstaceB(){
    // 已经实例化了,直接使用它
  }
}

return singletonB;

上面的这种做法是在JVM加载这个类时马上创建一个实例,因为JVM会在线程访问这个实例之前就创建出该实例,因此线程是安全的。但这相较于延迟实例化而言可能会出现资源的浪费。而且如果此类较大的情况下会时程序初始化时间加长。

/* 那么是否可以在使用延迟实例化的同时又不会造成线程不安全且增加访问效率呢?接下来就用双重检查加锁来改进一下。 */
 /* 双重锁单例模式 */
 */
public class SingletonC {
  private volatile static SingletonC singletonC;
  private SingletonC(){
  }
  public static SingletonC getInstanceC(){
    if (singletonC == null) {
      synchronized (SingletonC.class) {
        if (singletonC == null) {
          singletonC = new SingletonC();
        }
      }
    }
    return singletonC;
  }
}

L'esempio sopra verifica prima l'istanza, se non esiste entra nel blocco同步, dopo aver entrato nel blocco同步 verifica di nuovo, se è ancora null crea l'istanza, quindi singletonC = new SingletonC() verrà eseguito una volta sola, e dopo aver chiamato getInstanceC() direttamente tornerà direttamente all'istanza esistente, quindi a parte la prima chiamata, non seguirà il percorso del metodo同步 come nell'esempio due. Questo può ridurre il tempo di esecuzione di getInstanceC(). Si noterà che la parola chiave volatile, il cui ruolo è rendere singletonC visibile a tutti i thread dopo l'inizializzazione, in modo che più thread possano gestire correttamente la variabile SingletonC. Tuttavia, è necessario notare che la parola chiave volatile può essere utilizzata solo a partire da Java 5, se utilizzata in versioni precedenti potrebbe disattivare il doppio controllo.

Quando si utilizza il modello Singleton, se ci sono più classloader (caricatore di classi) è necessario specificare manualmente il classloader e specificare l'uso di un classloader. Poiché ogni classloader definisce uno spazio dei nomi, classloader diversi potrebbero caricare la stessa classe, il che potrebbe portare alla creazione di più istanze della classe Singleton.

Grazie per la lettura, speriamo che possa aiutare tutti, grazie per il supporto al nostro sito!

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright spetta ai rispettivi autori, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata la veridicità, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare