seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營銷培訓(xùn)

1、前言

1-1、 概述

  設(shè)計模式 = 某類特定問題的解決方案,那么單例模式是解決什么問題的解決方案呢?

  含義:單例  =  一個實例

  解決的問題:在任何時間內(nèi)只有一個類實例存在的模式

  解決方法:保證一個類只有一個實例化對象,并提供一個全局訪問入口

  本質(zhì):控制實例的數(shù)量

  注意:要合理的使用單例,避免單例成為瓶頸

  英文:Singleton

    類型:創(chuàng)建類模式

1-2、問題引入

模擬網(wǎng)站訪問數(shù)量統(tǒng)計功能:

+ View Code

結(jié)果:

1
2
3
4
是不是同一個網(wǎng)站?
不是
訪問量:1
訪問量:1

從結(jié)果看,兩個人訪問的不是一個網(wǎng)站實例,其實我們要實現(xiàn)的邏輯是,訪問同一個網(wǎng)站,計算訪問量,這顯然是不符合我們想要的

 

2、介紹

 2-1、分析引入的問題

  沖突:從上面的結(jié)果可以看出,網(wǎng)站計數(shù)器類操作的明顯不是同一個實例

  目標(biāo):所有訪問者操作同一個網(wǎng)站計數(shù)器類

  單例模式就是為了解決這類問題的解決方案:實現(xiàn)一個類只有一個實例化對象,并提供一個全局訪問入口

 

 2-2、解決引入的問題

解決:改造一下網(wǎng)站計數(shù)器類的實現(xiàn)代碼

+ View Code

再來看一下結(jié)果:

1
2
3
4
是不是同一個網(wǎng)站?
訪問量:1
訪問量:2

這次是對的?。?!

 

 2-3、實現(xiàn)原理

引入單例模式:一般實現(xiàn)方式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
    //1. 創(chuàng)建私有變量 instance(用以記錄 Singleton 的唯一實例)
    //2. 內(nèi)部進行實例化
    private static Singleton instance  = new  Singleton();
    //3. 把類的構(gòu)造方法私有化,不讓外部調(diào)用構(gòu)造方法實例化
    private Singleton() {
    }
    //4. 定義公有方法提供該類的全局唯一訪問點
    //5. 外部通過調(diào)用getInstance()方法來返回唯一的實例
    public static Singleton getInstance() {
        return instance;
    }
}

 

2-4、優(yōu)點、缺點

優(yōu)點: 
  1.在單例模式中,活動的單例只有一個實例,對單例類的所有實例化得到的都是相同的一個實例。這樣就防止其它對象對自己的實例化,確保所有的對象都訪問一個實例 
  2.單例模式具有一定的伸縮性,類自己來控制實例化進程,類在實例化進程上有相應(yīng)的伸縮性
  3.提供了對唯一實例的訪問入口
  4.由于在系統(tǒng)內(nèi)存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源,當(dāng)需要頻繁創(chuàng)建和銷毀的對象時單例模式無疑可以提高系統(tǒng)的性能
  5.允許可變數(shù)目的實例(可以根據(jù)實際情況需要,在單例模式的基礎(chǔ)上擴展做出雙例模式、多例模式)
  6.避免對共享資源的多重占用
缺點: 
  1.不適用于變化的對象,如果同一類型的對象總是要在不同的用例場景發(fā)生變化,單例就會引起數(shù)據(jù)的錯誤,不能保存彼此的狀態(tài)
  2.由于單利模式中沒有抽象層,因此單例類的擴展有很大的困難。 
  3.單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則” 
  4.濫用單例將帶來一些負面問題,如為了節(jié)省資源將數(shù)據(jù)庫連接池對象設(shè)計為的單例類,可能會導(dǎo)致共享連接池對象的程序過多而出現(xiàn)連接池溢出;如果實例化的對象長時間不被利用,系統(tǒng)會認為是垃圾而被回收,這將導(dǎo)致對象狀態(tài)的丟失

 

3、實現(xiàn)

3-1、餓漢模式、懶漢模式

餓漢模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.designmode;
 
/**
 * 餓漢模式(最簡單的形式)
 */
public class Singleton {
    private static  Singleton instance  = new  Singleton();
 
    private Singleton() {
    }
 
    public static Singleton getInstance() {
        return instance;
    }
}

應(yīng)用場景:

  要求直接在應(yīng)用啟動時加載并初始化
  單例對象要求初始化速度非???/p>

 

懶漢模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.designmode;
 
/**
 * 懶漢模式(最簡單的形式)
 */
public class Singleton {
    private static  Singleton instance  = null;
 
    private Singleton() {
    }
 
    public static Singleton newInstance() {
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

 應(yīng)用場景:

  單例初始化的操作耗時比較長(可以相應(yīng)縮短應(yīng)用啟動時間)
  單例只是在某個特定場景的情況下才會被使用,即按需延遲加載單例

 

對比:

  餓漢式:自動進行單例的初始化
  懶漢式:有需要的時候才手動調(diào)用getInstance()進行單例的初始化操作

3-2、多線程下的實現(xiàn)

在多線程的情況下:

  “餓漢式單例模式”:適用,因為JVM只會加載一次單例類
  “懶漢式單例模式”:不適用,因為“懶漢式”在創(chuàng)建單例時是線程不安全的,多個線程可能會并發(fā)調(diào)用 getInstance 方法從而出現(xiàn)重復(fù)創(chuàng)建單例對象的問題

下面有幾個解決方案:

方案1:同步鎖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入造成instance被多次實例化
package com.designmode;
 
public class Singleton {
    private static  Singleton instance  = null;
 
    private Singleton() {
    }
 
    public static  Singleton getInstance() {
        synchronized (Singleton.class){
           if(instance == null){
              instance = new Singleton();
           }
        }
      return instance;
   }
}

  

方案2:雙重校驗鎖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//在同步鎖的基礎(chǔ)上( synchronized (Singleton.class) 外)添加了一層if,這是為了在Instance已經(jīng)實例化后下次進入不必執(zhí)行 synchronized (Singleton.class) 獲取對象鎖,從而提高性能
package com.designmode;
 
public class Singleton {
    private static  Singleton instance  = null;
 
    private Singleton() {
    }
 
    public static  Singleton getInstance() {
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
   }
}

  

方案3:靜態(tài)內(nèi)部類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//在JVM進行類加載的時候會保證數(shù)據(jù)是同步的,我們采用內(nèi)部類實現(xiàn):在內(nèi)部類里面去創(chuàng)建對象實例
//只要應(yīng)用中不使用內(nèi)部類 JVM 就不會去加載這個單例類,也就不會創(chuàng)建單例對象,從而實現(xiàn)“懶漢式”的延遲加載和線程安全。
package com.designmode;
 
public class Singleton {
    //在裝載該內(nèi)部類時才會去創(chuàng)建單例對象
    private static class Singleton2{
        private static Singleton instance  = new Singleton();
    }
     
    private Singleton() {
    }
 
    public static Singleton getInstance() {
        return Singleton2.instance;
    }
}

  

方案4:枚舉類型

1
2
3
4
5
6
7
8
9
10
11
12
13
//最簡潔、易用的單例實現(xiàn)方式,(《Effective Java》推薦)
package com.designmode;
 
public enum Singleton{
    //定義一個枚舉的元素,它就是Singleton的一個實例
    INSTANCE;
    private Singleton() {
       
    }
    public void doSomething(){ 
         
    
}

調(diào)用方式:

1
Singleton.INSTANCE.doSomething();

  

4、總結(jié)

      設(shè)計模式 = 某類特定問題的解決方案,那么單例模式是解決什么問題的解決方案呢?

  含義:單例  =  一個實例

  解決的問題:在任何時間內(nèi)只有一個類實例存在的模式

  解決方法:保證一個類只有一個實例化對象,并提供一個全局訪問入口

  本質(zhì):控制實例的數(shù)量

  注意:要合理的使用單例,避免單例成為瓶頸

 

 

PS:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master

 

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7093947.html

   

如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力! 
如果標(biāo)題被標(biāo)記為轉(zhuǎn)載,轉(zhuǎn)載請注明原作者地址,詳見引用 
版權(quán)聲明,轉(zhuǎn)載請注明出處:http://www.cnblogs.com/JsonShare

http://www.cnblogs.com/JsonShare/p/7093947.html