簡介
單例模式(Singleton Pattern)是Java中最簡單的設計模式之一。屬于建立型模式。該模式隻涉及到一個單一的類,負責建立自己的對象,并且隻有單個的對象被建立。這個類提供了一種通路其唯一的對象的方式,可以直接通路,不需要執行個體化該類的對象。
意圖
保證一個類有且隻有一個執行個體,并提供一個通路它的全局通路點。
主要解決
一個全局使用的類頻繁的建立于銷毀
如何解決
判斷系統是否有這個單利,如果有則傳回,如果沒有就建立
關鍵代碼
構造函數是私有的,然後公開一個GetInstance方法
圖示
應用執行個體
一個黨有且隻有一個主席
地球有且隻有一個,從有地球這個單例開始,所有的動物都用這個單例而且隻有這個單例可用
登入子產品、配置子產品
幾種實作方式
1. 懶漢式
1.1 懶漢式-線程不安全
public class Singleton{
private static Singleton instance;
//讓構造函數為 private,這樣該類就不會被執行個體化
private Singleton(){}
public static Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
1.2 懶漢式-線程安全
public class Singleton{
private static Singleton instance;
//讓構造函數為 private,這樣該類就不會被執行個體化
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
1.1 最大的問題是不支援多線程,1.2加上鎖synchonized就支援了多線程,嚴格意義上講1.1不是單例模式。
優點:第一次調用的時候才初始化,避免記憶體浪費
缺點:必須加鎖synchonized才能保證單例,但加鎖會影響效率
2. 餓漢式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
餓漢式多線程安全,比較常用,但容易産生垃圾對象
優點:沒有加鎖,執行效率會提高
缺點:類加載是就初始化,浪費記憶體
它基于 classloder 機制避免了多線程的同步問題,不過,instance 在類裝載時就執行個體化
3. 雙驗鎖/雙重校驗鎖
public class Singleton{
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
這種方式安全且在多線程的方式下保持高性能
執行個體
singleton.java
public class Singleton{
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
SingletonPatternDemo.java
public class SingletonPatternDemo {
public static void main(String []args){
Singleton object = Singleton.getInstance();
Singleton object2 = Singleton.getInstance();
System.out.println("End~~~~~~~~~~~");
}
}
推薦1:靜态内部類
public class Singleton1 {
private static class MySingleton {
public static final Singleton1 INSTANCE = new Singleton1();
}
private Singleton1() {
}
public static Singleton1 getInstance() {
return MySingleton.INSTANCE;
}
由于靜态内部類MyS
ingleton
隻有在
getInstance()
方法第一次被調用時,才會被加載,而且構造函數為private,是以該種方式實作了懶漢式的單例模式。不僅如此,根據JVM本身機制,靜态内部類的加載已經實作了線程安全。
推薦2:枚舉
public interface MySingleton {
void doSomething();
}
public enum Singleton implements MySingleton {
INSTANCE {
@Override
public void doSomething() {
System.out.println("complete singleton");
}
};
public static MySingleton getInstance() {
return Singleton.INSTANCE;
}
}
- 枚舉類實作其實省略了
類型的構造函數private
- 枚舉類的域(field)其實是相應的enum類型的一個執行個體對象