目錄
概述
單例模式是一種創建型模式
許多時候整個系統只需要擁有一個的全局對象,這樣有利於我們協調系統整體的行爲。比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然後服務進程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在複雜環境下的配置管理。
適用場景
- 需要生成唯一序列的環境
- 需要頻繁實例化然後銷燬的對象。
- 創建對象時耗時過多或者耗資源過多,但又經常用到的對象。
- 方便資源相互通信的環境
優缺點
優點:
-
在內存中只有一個對象,節省內存空間;
-
避免頻繁的創建銷燬對象,可以提高性能;
-
避免對共享資源的多重佔用,簡化訪問;
-
爲整個系統提供一個全局訪問點。
缺點:
-
不適用於變化頻繁的對象;
-
濫用單例將帶來一些負面問題,如爲了節省資源將數據庫連接池對象設計爲的單例類,可能會導致共享連接池對象的程序過多而出現連接池溢出;
-
如果實例化的對象長時間不被利用,系統會認爲該對象是垃圾而被回收,這可能會導致對象狀態的丟失;
實現
餓漢式
使用靜態變量來實現
public class EHan1 {
//使用靜態變量,沒有線程安全問題,在類加載階段就已經進行
private static EHan1 instance=new EHan1();
private EHan1(){
}
//提供靜態方法,用方法而不用對象可以提供更好的封裝性。
public static EHan1 getInstance(){
return instance;
}
}
使用靜態代碼塊來實現
public class EHan2 {
//使用靜態變量,沒有線程安全問題,在類加載階段就已經進行
private static EHan2 instance;
private EHan2(){
}
static {
instance=new EHan2();
}
//提供靜態方法,用方法而不用對象可以提供更好的封裝性。
public static EHan2 getInstance(){
return instance;
}
}
枚舉
enum Singeleton{
INSTANCE;
}
//屬於餓漢式方法
//是線程安全的
//不能被反射
//可以被反序列化
public class Enum {
public static void main(String[] args) {
Singeleton singeleton=Singeleton.INSTANCE;
}
}
懶漢式
線程不安全
public class LHan1 {
//線程不安全
private static LHan1 instance;
private LHan1(){
}
public LHan1 getInstance(){
if(instance==null){
instance= new LHan1();
}
return instance;
}
}
雙重檢查(線程安全)
public class DoubleCheck {
//線程安全
//volatile 構造方法的指令和賦值指令有可能被重排序
private static volatile DoubleCheck instance;
private DoubleCheck(){
}
public static DoubleCheck getInstance(){
if(instance==null){
synchronized (DoubleCheck.class) {
//防止首次創建時多個線程併發問題
if(instance==null)
instance=new DoubleCheck();
}
}
return instance;
}
}
靜態內部類--線程安全
public class StaticInnerClass {
//懶漢式 靜態內部類只有在類第一次被使用的時候纔會被裝載
//volatile 構造方法的指令和賦值指令有可能被重排序
private static volatile StaticInnerClass instance;
private StaticInnerClass(){
}
//寫一個靜態內部類
private static class StaticInnerInstace{
private static final StaticInnerClass instace=new StaticInnerClass();
}
//提供一個靜態公有方法,直接返回成員變量
public static synchronized StaticInnerClass getInstance(){
return StaticInnerInstace.instace;
}
}