/**
* 單例模式 ~ 懶漢式
*
* @author LTP 2021/11/9
*/
class Singleton_lazy {
private static Singleton_lazy mInstance;
private Singleton_lazy() {
}
public static Singleton_lazy getInstance() {
if (mInstance == null) {
mInstance = new Singleton_lazy();
}
return mInstance;
}
}
2、線程安全的懶漢式
/**
* 單例模式 ~ 線程安全的懶漢式
*
* @author LTP 2021/11/9
*/
class Singleton_lazySync {
private static Singleton_lazySync mInstance;
private Singleton_lazySync() {
}
public static synchronized Singleton_lazySync getInstance() {
if (mInstance == null) {
mInstance = new Singleton_lazySync();
}
return mInstance;
}
}
-
特點:在獲取單例的方法上加synchronized關(guān)鍵字保證線程安全捷沸,但每次獲取都加鎖效率比較低
3摊沉、雙重校驗鎖DCL(double check lock)
/**
* 單例模式 ~ 雙重校驗鎖DCL(Double check lock)
* 是針對線程安全的懶漢式的優(yōu)化版本
*
* @author LTP 2021/11/5
*/
public class Singleton_DCL {
/**
* volatile關(guān)鍵字(可見性、防止指令重排痒给、不保證原子性)此處用到了防止指令重排的特性
* 在一個線程分配了mInstance所指向的內(nèi)存地址说墨,但并未初始化時(發(fā)生指令重排),
* 第二個線程在第一個判空的位置會判斷mInstance不為空從而直接返回當(dāng)前mInstance苍柏,但事實上mInstance并未初始化而造成錯誤
* 具體參考:https://blog.csdn.net/llllllkkkkkooooo/article/details/115360630
*/
private static volatile Singleton_DCL mInstance;
private Singleton_DCL() {
}
public static Singleton_DCL getInstance() {
// 第一個判空是減少synchronized加鎖尼斧,提高效率
if (mInstance == null) {
// 執(zhí)行位置1
synchronized (Singleton_DCL.class) {
// 第二次判空是防止有多個線程調(diào)用getInstance()時都執(zhí)行在第一次判空之后并阻塞在synchronized之前(執(zhí)行位置1)
// 從而導(dǎo)致一個線程中初始化后下一個線程繼續(xù)初始化,從而破壞單例
if (mInstance == null) {
mInstance = new Singleton_DCL();
}
}
}
return mInstance;
}
}
4、餓漢式
/**
* 單例模式 ~ 餓漢式
*
* @author LTP 2021/11/9
*/
class Singleton_hungry {
private static final Singleton_hungry mInstance = new Singleton_hungry();
private Singleton_hungry() {
System.out.println("構(gòu)造器");
}
public static Singleton_hungry getInstance() {
return mInstance;
}
// 執(zhí)行順序:構(gòu)造器-main
public static void main(String[] args) {
System.out.println("main");
Singleton_hungry instance =Singleton_hungry.getInstance();
}
}
-
特點:直接在類加載時初始化單例對象熄捍,保證唯一性
5烛恤、靜態(tài)內(nèi)部類
/**
* 單例模式 ~ 靜態(tài)內(nèi)部類
* 相比較餓漢式的好處是:第一次加載Singleton_staticInnerClass并不會初始化mInstance(調(diào)用構(gòu)造器),
* 只有在調(diào)用getInstance()時,才會加載SingletonHolder從而初始化mInstance,
* 參考:https://blog.csdn.net/weixin_30530523/article/details/96640126
*
* @author LTP 2021/11/9
*/
class Singleton_staticInnerClass {
private Singleton_staticInnerClass() {
System.out.println("構(gòu)造器");
}
public static Singleton_staticInnerClass getInstance() {
return SingletonHolder.mInstance;
}
private static class SingletonHolder {
public static final Singleton_staticInnerClass mInstance = new Singleton_staticInnerClass();
}
// 執(zhí)行順序:main-構(gòu)造器
public static void main(String[] args) {
System.out.println("main");
Singleton_staticInnerClass instance =Singleton_staticInnerClass.getInstance();
}
}
6、枚舉
/**
* 枚舉宾添,一般不用枚舉,可讀性差柜裸,而且使用枚舉會造成內(nèi)存加大(每個枚舉類都會申明成一個靜態(tài)變量)缕陕,Android不推薦
*
* @author LTP 2021/11/9
*/
class Singleton_enum {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.INSTANCE;
}
enum SingleTon {
INSTANCE
}
}
-
特點:簡單,可讀性差疙挺,而且Android不推薦使用枚舉(加大內(nèi)存占用)
7扛邑、容器類
package com.btpj.design_pattern.singleton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 單例模式 ~ 容器
* 多種單例類統(tǒng)一管理,在使用時根據(jù)key獲取對象對應(yīng)類型的對象铐然。
* 這種方式使得我們可以管理多種類型的單例蔬崩,并且在使用時可以通過統(tǒng)一的接口進行獲取操作恶座,
* 降低了用戶的使用成本,也對用戶隱藏了具體實現(xiàn)沥阳,降低了耦合度
*
* @author LTP 2021/11/5
*/
public class Singleton_map {
/**
* 使用Map容器類統(tǒng)一管理各單例實例
*/
private static Map<String, Object> mObjMap = new ConcurrentHashMap<>();
private Singleton_map() {
}
/**
* 將實例保存至Map容器
*
* @param key key
* @param instance 實例
*/
public static void addInstance(String key, Object instance) {
if (!mObjMap.containsKey(key)) {
mObjMap.put(key, instance);
}
}
/**
* 根據(jù)key獲取單例類
*
* @param key key
* @return 獲取到的單例類
*/
public static Object getInstance(String key) {
return mObjMap.get(key);
}
}
-
特點:可統(tǒng)一管理多種單例類跨琳,降低了用戶的使用成本,也對用戶隱藏了具體實現(xiàn)桐罕,降低了耦合度
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者