大话设计模式—单例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。
這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
單例模式:
1、保證一個類僅有一個實例,并提供一個訪問它的全局訪問點;
2、當一個全局使用的類被頻繁的創建和銷毀;或者你要控制實例的數目,節省系統資源的時候,可以考慮使用單例模式;
3、實現:判斷系統是否存在這個單例,如果存在則返回,否則,創建;
4、構造函數私有;
注意:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
單例模式的幾種實現方式:
1、懶漢式(lazy loading)
package com.dfcDemo;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;/*** 第一次調用才初始化,避免內存浪費。* 但是必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。* getInstance() 的性能對應用程序不是很關鍵(該方法使用不太頻繁)* @author lmb**/ public class SingletonLazy {private static Log logger = LogFactory.getLog(SingletonLazy.class);private static SingletonLazy instance;private SingletonLazy(){logger.info("singleton is constructing");}public static synchronized SingletonLazy getInstance(){if(instance == null){instance = new SingletonLazy();//用到該類實例的時候再去初始化}return instance;}public static void main(String[] args) {logger.info("main方法開始執行---");//同時開啟100個線程去調用getInstance()方法for (int i = 0; i <= 100; i++) {new Thread(new Runnable(){@Overridepublic void run() {SingletonLazy.getInstance();}}).start();}logger.info("main方法執行結束---");} }運行結果:
2016-03-17 11:16:04 INFO com.dfcDemo.SingletonLazy - main方法開始執行--- 2016-03-17 11:16:04 INFO com.dfcDemo.SingletonLazy - singleton is constructing 2016-03-17 11:16:04 INFO com.dfcDemo.SingletonLazy - main方法執行結束---2、餓漢式
package com.dfcDemo;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;/*** 類加載時就初始化,浪費內存* @author lmb**/ public class SingletonHungry {private static Log logger = LogFactory.getLog(SingletonHungry.class);private static SingletonHungry instance = new SingletonHungry();//首次加載該類的時候就初始化private SingletonHungry(){logger.info("singleton is constructing");}public static SingletonHungry getInstance(){return instance;}public static void main(String[] args) {logger.info("main方法開始執行---");//同時開啟100個線程去調用getInstance()方法for (int i = 0; i <= 100; i++) {new Thread(new Runnable(){@Overridepublic void run() {SingletonHungry.getInstance();}}).start();}logger.info("main方法執行結束---");} }運行結果:
2016-03-17 11:16:23 INFO com.dfcDemo.SingletonHungry - singleton is constructing 2016-03-17 11:16:23 INFO com.dfcDemo.SingletonHungry - main方法開始執行--- 2016-03-17 11:16:23 INFO com.dfcDemo.SingletonHungry - main方法執行結束---3、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)
實現原理:我們不讓線程每次都加鎖,而只是在實例未被創建的時候再加鎖。同時也能保證多線程的安全,對于instance存在的情況就直接返回;當instance不存在,并且同時有兩個線程調用getInstance()方法時,它們都可以通過第一重instance == null判斷,然后由于synchronizd鎖機制,兩個線程只有一個能進入,另一個在外排隊等候,必須要其中的一個進入并出來之后另一個才能進入。如果沒有了第二重的instance == null的判斷,則第一個線程創建了實例,第二個線程還是可以載繼續創建實例的。
package com.dfcDemo;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;/*** 這種方式采用雙鎖機制,安全且在多線程情況下能保持高性能;* getInstance() 的性能對應用程序很關鍵* @author lmb**/ public class SingletonDCL {private static Log logger = LogFactory.getLog(SingletonDCL.class);/*** 用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改后的最新的值,* 即jvm虛擬機只是保證從主內存加載到線程工作內存的值是最新的;*/private volatile static SingletonDCL instance;private SingletonDCL(){logger.info("singleton is constructing");}public static SingletonDCL getInstance(){if (instance == null) {synchronized (SingletonDCL.class) {if (instance == null) {instance = new SingletonDCL();//用到該類實例的時候再去初始化}}}return instance;}public static void main(String[] args) {logger.info("main方法開始執行---");//同時開啟100個線程去調用getInstance()方法for (int i = 0; i <= 100; i++) {new Thread(new Runnable(){@Overridepublic void run() {SingletonDCL.getInstance();}}).start();}logger.info("main方法執行結束---");} }運行結果:
2016-03-17 11:30:55 INFO com.dfcDemo.SingletonDCL - main方法開始執行--- 2016-03-17 11:30:55 INFO com.dfcDemo.SingletonDCL - singleton is constructing 2016-03-17 11:30:55 INFO com.dfcDemo.SingletonDCL - main方法執行結束---比較:
由于餓漢式,即靜態初始化的方式,它是類一加載就實例化的對象,所以要提前占用系統資源。而懶漢式,又會面臨著多線程訪問的安全性問題,需要做雙重鎖定這樣的處理才可以保證安全。所以,到底是用哪一種方式取決于實際的需求。
實用類與單例類比較:
實用類通常也會采用私有化的構造方法來避免其有實例,但它們還是有很多不同的:
1、實例類不保存狀態,僅提供一些靜態方法或靜態屬性,而單例類是有狀態的;
2、實用類不能用于繼承和多態,而單例類雖然實例唯一,但是可以有子類來繼承;
3、實用類是一些方法屬性的集合而單例卻有著唯一的對象實例。
總結
以上是生活随笔為你收集整理的大话设计模式—单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Class.getResource()、
- 下一篇: 大话设计模式—原型模式