單例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
注意:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
懶漢模式(線程不安全方式 不推薦 新手一般會這麼寫)
/**
* 懶漢模式
* 單例實例在第一次使用時被創建 容易出bug 線程不安全的
*/
public class SingletonExample {
//私有構造對象
private SingletonExample(){
}
//單例對象
private static SingletonExample instance = null;
//靜態工廠方法
public static SingletonExample getInstance(){
if(instance == null){
instance = new SingletonExample();
}
//這種方法 == null 在單線程下沒什麼問題,多線程下容易出現問題,因爲可能同時有兩個以上的線程走到if裏
return instance;
}
}
懶漢模式(線程安全方式,加synchronized 不推薦)
/**
* 懶漢模式
* 單例實例在第一次使用時被創建 加了synchronized有開銷
*/
@ThreadSafe
public class SingletonExample3 {
//私有構造對象
private SingletonExample3(){
}
//單例對象
private static SingletonExample3 instance = null;
//靜態工廠方法 有性能開銷
public static synchronized SingletonExample3 getInstance(){
if(instance == null){
instance = new SingletonExample3();
}
return instance;
}
}
懶漢模式(雙重檢測,但是仍然線程不安全原因是多線程下指令重排!!)
/**
* 懶漢模式 -》 雙重同步鎖單例模式
* 單例實例在第一次使用時被創建
*/
public class SingletonExample4 {
//私有構造對象
private SingletonExample4(){
}
//1。memory = allocate() 分配對象內存空間
//2。ctoInstance() 初始化對象
//3。instance = memory 設置instance指向剛分配的內存
//JVM和cpu優化 多線程下發生了指令重排
//1。memory = allocate() 分配對象內存空間
//3。instance = memory 設置instance指向剛分配的內存
//2。ctoInstance() 初始化對象
// 雙重檢測機制出現問題
//單例對象
private static SingletonExample4 instance = null;
//靜態工廠方法 有性能開銷
public static SingletonExample4 getInstance(){
if(instance == null){//雙重檢測機制 //B
synchronized(SingletonExample.class) {//同步鎖
if (instance == null){
instance = new SingletonExample4(); // A線程執行到這時,完成了 指令的 1 ,3 還沒進行初始化。這是B那個位置發現已經不爲null了直接就返回回去了。但是 真實的時instance還沒初始化完。
}
}
}
return instance;
}
}
懶漢模式(雙重檢測,加volatile 禁止指令重排, 推薦 )
/**
* 懶漢模式 -》 雙重同步鎖單例模式
* 單例實例在第一次使用時被創建
*/
public class SingletonExample5 {
//私有構造對象
private SingletonExample5(){
}
//1。memory = allocate() 分配對象內存空間
//2。ctoInstance() 初始化對象
//3。instance = memory 設置instance指向剛分配的內存
//限制發生指令重排
//單例對象 volatile 加上雙重檢測機制來禁止 指令重排
private volatile static SingletonExample5 instance = null;
//靜態工廠方法 有性能開銷
public static SingletonExample5 getInstance(){
if(instance == null){//雙重檢測機制 //B
synchronized(SingletonExample.class) {//同步鎖
if (instance == null){
instance = new SingletonExample5(); // A
}
}
}
return instance;
}
}
餓漢模式(推薦)
/**
* 餓漢模式
* 單例實例類裝載時進行創建 不足當單例模式過多時,可能會影響性能問題,如果最終沒調用,會造成資源浪費。 線程安全的
*/
public class SingletonExample2 {
//私有構造對象
private SingletonExample2(){
}
//單例對象
private static SingletonExample2 instance = new SingletonExample2();
//靜態工廠方法
public static SingletonExample2 getInstance(){
return instance;
}
}
餓漢模式(推薦)
/**
* 餓漢模式
* 單例實例類裝載時進行創建
*/
public class SingletonExample6 {
//私有構造對象
private SingletonExample6(){
}
//單例對象
private static SingletonExample6 instance = null;
static {
instance = new SingletonExample6();
}
//靜態工廠方法
public static SingletonExample6 getInstance(){
return instance;
}
public static void main(String[] args) {
System.out.println(getInstance());
System.out.println(getInstance());
}
}
枚舉(最安全 最推薦)
/**
* 枚舉模式 最安全
*/
public class SingletonExample7 {
private SingletonExample7(){
}
public static SingletonExample7 getInstance(){
return Singleton.INSTANCE.getInstance();
}
//私有枚舉類
private enum Singleton{
INSTANCE;
private SingletonExample7 singleton;
//JVM 保證這個方法絕對只調用一次
Singleton(){
singleton = new SingletonExample7();
}
public SingletonExample7 getInstance(){
return singleton;
}
}
}