設計模式(一)單例模式的七種寫法

1. 餓漢模式

public class Singleton {  private static Singleton instance = new Singleton();  private Singleton (){}public static Singleton getInstance() {  return instance;  }  }
View Code

這種方式在類加載時就完成了初始化,所以類加載較慢,但獲取對象的速度快。 這種方式基于類加載機制避免了多線程的同步問題,但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance顯然沒有達到懶加載的效果。

2. 懶漢模式(線程不安全)

public class Singleton {  private static Singleton instance;  private Singleton (){}   public static Singleton getInstance() {  if (instance == null) {  instance = new Singleton();  }  return instance;  }  }
View Code

懶漢模式申明了一個靜態對象,在用戶第一次調用時初始化,雖然節約了資源,但第一次加載時需要實例化,反映稍慢一些,而且在多線程不能正常工作。

3. 懶漢模式(線程安全)

public class Singleton {  private static Singleton instance;  private Singleton (){}public static synchronized Singleton getInstance() {  if (instance == null) {  instance = new Singleton();  }  return instance;  }  }
View Code

這種寫法能夠在多線程中很好的工作,但是每次調用getInstance方法時都需要進行同步,造成不必要的同步開銷,而且大部分時候我們是用不到同步的,所以不建議用這種模式。

4. 雙重檢查模式 (DCL)

public class Singleton {  private volatile static Singleton singleton;  private Singleton (){}   public static Singleton getInstance() {  if (instance== null) {  synchronized (Singleton.class) {  if (instance== null) {  instance= new Singleton();  }  }  }  return singleton;  }  }
View Code

這種寫法在getSingleton方法中對singleton進行了兩次判空,第一次是為了不必要的同步,第二次是在singleton等于null的情況下才創建實例。在這里用到了volatile關鍵字,不了解volatile關鍵字的可以查看Java多線程(三)volatile域這篇文章,在這篇文章我也提到了雙重檢查模式是正確使用volatile關鍵字的場景之一。
在這里使用volatile會或多或少的影響性能,但考慮到程序的正確性,犧牲這點性能還是值得的。 DCL優點是資源利用率高,第一次執行getInstance時單例對象才被實例化,效率高。缺點是第一次加載時反應稍慢一些,在高并發環境下也有一定的缺陷,雖然發生的概率很小。DCL雖然在一定程度解決了資源的消耗和多余的同步,線程安全等問題,但是他還是在某些情況會出現失效的問題,也就是DCL失效,在《java并發編程實踐》一書建議用靜態內部類單例模式來替代DCL。

5. 靜態內部類單例模式

public class Singleton { private Singleton(){}public static Singleton getInstance(){  return SingletonHolder.sInstance;  }  private static class SingletonHolder {  private static final Singleton sInstance = new Singleton();  }  
}
View Code

第一次加載Singleton類時并不會初始化sInstance,只有第一次調用getInstance方法時虛擬機加載SingletonHolder 并初始化sInstance ,這樣不僅能確保線程安全也能保證Singleton類的唯一性,所以推薦使用靜態內部類單例模式。

6. 枚舉單例

public enum Singleton {  INSTANCE;  public void doSomeThing() {  }  }
View Code

默認枚舉實例的創建是線程安全的,并且在任何情況下都是單例,上述講的幾種單例模式實現中,有一種情況下他們會重新創建對象,那就是反序列化,將一個單例實例對象寫到磁盤再讀回來,從而獲得了一個實例。反序列化操作提供了readResolve方法,這個方法可以讓開發人員控制對象的反序列化。在上述的幾個方法示例中如果要杜絕單例對象被反序列化是重新生成對象,就必須加入如下方法:

private Object readResolve() throws ObjectStreamException{
return singleton;
}
View Code

枚舉單例的優點就是簡單,但是大部分應用開發很少用枚舉,可讀性并不是很高,不建議用。

7. 使用容器實現單例模式

public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String,Object>();private Singleton() { }public static void registerService(String key, Objectinstance) {if (!objMap.containsKey(key) ) {objMap.put(key, instance) ;}}public static ObjectgetService(String key) {return objMap.get(key) ;}
}
View Code

用SingletonManager 將多種的單例類統一管理,在使用時根據key獲取對象對應類型的對象。這種方式使得我們可以管理多種類型的單例,并且在使用時可以通過統一的接口進行獲取操作,降低了用戶的使用成本,也對用戶隱藏了具體實現,降低了耦合度。

總結

到這里七中寫法都介紹完了,至于選擇用哪種形式的單例模式,取決于你的項目本身,是否是有復雜的并發環境,還是需要控制單例對象的資源消耗。

?

8.注意事項

1.使用反射能夠破壞單例模式,所以應該慎用反射

1 Constructor con = Singleton.class.getDeclaredConstructor();
2 con.setAccessible(true);
3 // 通過反射獲取實例
4 Singleton singeton1 = (Singleton) con.newInstance();
5 Singleton singeton2 = (Singleton) con.newInstance();
6 System.out.println(singeton1==singeton2);//結果為false,singeton1和singeton2將是兩個不同的實例
  • 可以通過當第二次調用構造函數時拋出異常來防止反射破壞單例,以懶漢式為例:
     1 public class Singleton {
     2     private static boolean flag = true;
     3     private static Singleton single = null;
     4 
     5     private Singleton() {
     6         if (flag) {
     7             flag = !flag;
     8         } else {
     9             throw new RuntimeException("單例模式被破壞!");
    10         }
    11     }
    12 
    13     public static Singleton getInstance() {
    14         if (single == null) {
    15             single = new Singleton();
    16         }
    17         return single;
    18     }
    19 }

2.反序列化時也會破壞單例模式,可以通過重寫readResolve方法避免,以餓漢式為例

 1 public class Singleton implements Serializable {
 2     private Singleton() {
 3     }
 4 
 5     private static final Singleton single = new Singleton();
 6 
 7     public static Singleton getInstance() {
 8         return single;
 9     }
10 
11     private Object readResolve() throws ObjectStreamException {//重寫readResolve()
12         return single;//直接返回單例對象
13     }
14 }

?

轉載于:https://www.cnblogs.com/ganchuanpu/p/6618995.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/541694.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/541694.shtml
英文地址,請注明出處:http://en.pswp.cn/news/541694.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

scala 字符串轉換數組_如何在Scala中將字節數組轉換為字符串?

scala 字符串轉換數組Byte Array in Scala is an array of elements of a byte type. String in Scala is a collection of the character data type. Scala中的字節數組是字節類型的元素的數組。 Scala中的String是字符數據類型的集合。 將字節數組轉換為字符串 (Convert byt…

智能關機軟件 c語言,智能關機軟件

智能關機軟件是一款免費共享關機軟件。智能關機軟件不但具有定時關機、自動關機的功能&#xff0c;而且還可以進行定時提醒信息、打開文件、打開網頁、重啟計算機、注銷用戶、鎖定計算機、計算機休眠、計算機待機、關閉顯示器&#xff0c;并且可以進行多任務計劃&#xff0c;可…

wget: command not found

-bash: wget: command not found的兩種解決方法 今天給服務器安裝新LNMP環境時&#xff0c;wget 時提示 -bash:wget command not found,很明顯沒有安裝wget軟件包。一般linux最小化安裝時&#xff0c;wget不會默認被安裝。可以通過以下兩種方法來安裝&#xff1a;1、rpm 安裝rp…

數據庫數據規范化看不懂_數據庫管理系統中的規范化

數據庫數據規范化看不懂DBMS中的規范化 (Normalization in DBMS) Every table must have a single idea. The method by which we divide tables approximately is called normalization and the rest used for normalization is a functional dependency. For the normalizati…

c 語言開發一個四則運算器,C++實現四則運算器(無括號)

本文實例為大家分享了C實現無括號的四則運算器的具體代碼&#xff0c;供大家參考&#xff0c;具體內容如下完成度更高的帶括號版本可以看C實現四則運算器(帶括號)對于無括號的計算器&#xff0c;實現起來比較容易&#xff0c;下面讓我們一步步實現。舉例首先明確需要實現怎樣的…

iOS開發之解決系統數字鍵盤無文字時delete鍵無法監聽的技巧

最近在做用戶登錄獲取驗證碼時添加圖形驗證碼功能&#xff0c;就是只有正確輸入圖形驗證碼才能收到后臺發送的短信驗證碼。效果如下&#xff1a; 看起來雖然是個小功能&#xff0c;但是實際操作起來&#xff0c;會發現蘋果給我們留下的坑&#xff0c;當然更多的是自己給自己挖的…

c ++查找字符串_C ++結構| 查找輸出程序| 套裝1

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>#include <math.h>using namespace std;struct st {int A NULL;int B abs(EOF EOF);} S;int main(){cout << S.A << " " << S.B;return 0;}Output: 輸出&#xff1a…

二級c語言加油,二級C語言 備考指南及常見問題(2013版)

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓3、關于上機操作部分的復習最好買一本上機題庫方面的教材&#xff0c;或打印、閱讀南開百題之類的電子文檔。配合上機模擬軟件(無紙化考試軟件)&#xff0c;上機練習是必須的。上機軟件一般有100套題多一點&#xff0c;每套有程序填…

開放定址散列表

再散列之后散列函數要重新計算。 // kaifangliaobiao.cpp : 定義控制臺應用程序的入口點。 //使用平方探測解決沖突問題時&#xff0c;散列表至少空一半時&#xff0c;總能插入一個新的元素#include "stdafx.h" #include<iostream> using namespace std;#ifnde…

合并兩個鏈表數據結構c語言,合并兩個鏈表.

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #define N1 10#define N2 10struct list{int date ;struct list *next;};main(){struct list *p1,*p2,*p3,*p4,*head,*head1,*head2,*p;int n0;head1head2NULL;p1p2(struct list *)malloc(sizeof(struct list));p1->da…

c ++查找字符串_C ++結構| 查找輸出程序| 套裝2

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>using namespace std;int main(){typedef struct{int A;char* STR;} S;S ob { 10, "india" };S* ptr;ptr &ob;cout << ptr->A << " " << ptr->STR[2];…

連接fiddler后手機無法顯示無網絡

升級了fiddler到4.6版本&#xff0c;手機設置代理后提示無網絡&#xff0c;試試以下解決方法&#xff1a; 1.fiddler升級后對應的.net framework也要升級&#xff0c;安裝最新的.net framework 4.6&#xff0c;升級安裝后&#xff0c;可以正確抓包啦 2.如果上述方法無效&#x…

android 人臉解鎖 鎖屏動畫,人臉保護鎖(人臉識別鎖屏)

這是一款十分炫酷的鎖屏工具&#xff0c;還記得電影中的特工所用的人臉識別鎖嗎&#xff1f;這款應用也能讓你過過癮&#xff01;人臉識別鎖屏安卓版是一款用人臉做密碼來打開手機屏保鎖的一個APP。不僅可以作屏保鎖&#xff0c;也可以單獨保護某些重要程序不被偷窺,例如查看短…

dbms_排名前50位的DBMS面試問答

dbms1) What are the drawbacks of the file system which is overcome on the database management system? 1)在數據庫管理系統上克服的文件系統有哪些缺點&#xff1f; Ans: Data redundancy & isolation, difficulty in accessing data, data isolation, and integri…

linux時間

CST代表中國標準時間rtc實時時鐘linux主要有兩種時間硬件時鐘 clock系統時鐘 date修改時間 date 03300924必須是兩位或者 date -s 2017:03:30將系統時間同步到硬件時間 hwclock -w將硬件時間同步到系統時間 hwclock -s轉載于:https://blog.51cto.com/12372297/1911608

查找Python中給定字符串的所有排列

Python itertools Module Python itertools模塊 "itertools" are an inbuilt module in Python which is a collection of tools for handling iterators. It is the most useful module of Python. Here, a string is provided by the user and we have to print a…

android 圖片疊加xml,Android實現圖片疊加效果的兩種方法

本文實例講述了Android實現圖片疊加效果的兩種方法。&#xff0c;具體如下&#xff1a;效果圖&#xff1a;第一種&#xff1a;第二種&#xff1a;第一種是通過canvas畫出來的效果:public void first(View v) {// 防止出現Immutable bitmap passed to Canvas constructor錯誤Bit…

Win10系列:VC++ 定時器

計時器機制俗稱"心跳"&#xff0c;表示以特定的頻率持續觸發特定事件和執行特定程序的機制。在開發Windows應用商店應用的過程中&#xff0c;可以使用定義在Windows::UI::Xaml命名空間中的DispatcherTimer類來創建計時器。DispatcherTimer類包含了如下的成員&#xf…

dbms系統 rdbms_DBMS與傳統文件系統之間的區別

dbms系統 rdbmsIntroduction 介紹 DBMS and Traditional file system have some advantages, disadvantages, applications, functions, features, components and uses. So, in this article, we will discuss these differences, advantages, disadvantages and many other …

android 百度地圖api密鑰,Android百度地圖開發獲取秘鑰之SHA1

最近在做一個關于百度地圖的開發。不過在正式開發之前還必須要在百度地圖API官網里先申請秘鑰&#xff0c;而在申請秘鑰的過程中&#xff0c;就需要獲取一個所謂的SHA1值。如上所示&#xff0c;但是由于不是正式開發&#xff0c;所以以上的發布版和開發版的SHA1可以先填寫相同。…