設計模式——單例模式

1、引言

  今天筆者想寫的設計模式——單例模式,其意圖就是爲了使系統有且僅有一個實例化,也就是一個對象我只有new一次就夠了,也是像咱們平凡人同樣,婚結一次就夠了,可是如今的社會啊,我只能以「理想很豐滿,現實很骨感」來形容了,讓咱們一塊兒瞭解下單例設計模式吧。java

2、單例模式

  1. 定義:它是比較簡單的一個模式,就是確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例。算法

  2. 類圖:單純的單例模式,其實就一個類,因此在此處就省略一下類圖吧。數據庫

3、單例模式示例

  1. 懶漢式  設計模式

package com.pattern.singleton.core;

/**
 * 單例——懶漢式
 * 典型的以時間換空間方式
 * @author yemaoan
 *
 */
public class Singleton {

    private static Singleton singleton;
    
    private Singleton() {    //注意是private哦
        
    }
    
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

  2. 飽漢式安全

package com.pattern.singleton.core;

/**
 * 單例——餓漢式
 * 典型的以空間換時間方式
 * @author yemaoan
 *
 */
public class Singleton {

    public static Singleton singleton = new Singleton();
    
    private Singleton() {
        
    }
    
    public static Singleton getInstance() {
        return singleton;
    }
}

4、單例模式應用

  單例看起來就是如上面的兩種狀況同樣,至關簡單,若是真的這麼認爲單例就這樣完了,那你可能真的可能完了。說不定哪一天你的婚姻真的因插入一個小三給毀了,固然,言重了,那讓咱們分析一下弊病吧。多線程

  在大數據的背景下,併發處理就不可或缺了,而只是簡簡單單的單例就可能經不起壓力測試了,從源碼分析上,很容易就發如今問題所在了。怎麼解決了,暫且能夠在getSingleton()方法前加個關鍵字synchronized來解決吧。併發

  解決線程不安全的方法挺多的,具體狀況具體分析吧。筆者推薦一個:ide

package com.pattern.singleton.core;

/**
 * 利用static在JVM啓動時只實例化一次確保對象惟一
 * @author yemaoan
 *
 */
public class Singleton {

    private Singleton() {
        
    }

    public static Singleton getInstance() {
        return SingletonInstance.instance;
    }

    //靜態類——在Java應用啓動只實例化一次,確實instance的惟一
    private static class SingletonInstance {
        static Singleton instance = new Singleton();
    }
    
}

   寫個例子測試一下吧——就拿上文寫的策略算法映射Service來寫吧,爲何這麼選擇呢,也許有這麼一個需求,筆者認爲,這個類其實也就是一個服務類,不少細節是在開發前就已經配置好的,或者說在數據庫裏已經定義好的,這樣的話,就想當一個工具類。工具

package com.pattern.stategy.factory;

import java.util.HashMap;
import java.util.Map;

import com.pattern.stratgy.core.Car;
import com.pattern.stratgy.core.Plane;
import com.pattern.stratgy.core.Train;

/**
 * 算法映射——改裝成單例
 * @author yemaoan
 *
 */
public class ContentService {

    private Map<String, Class> contentMap = new HashMap<String, Class>();
    
    private ContentService() {
        contentMap.put("train", Train.class);
        contentMap.put("plane", Plane.class);
        contentMap.put("car", Car.class);
    }
    
    public static ContentService contentServiceInstance() {
        return ContentServiceInstance.instance;
    }

    private static class ContentServiceInstance {
        static ContentService instance = new ContentService();
    }
    
    public Class get(String key) {
        return contentMap.get(key);
    }
    
}

  調用者代碼:源碼分析

package com.pattern.singleton.client;

import java.util.ArrayList;
import java.util.List;

import com.pattern.stategy.factory.ContentService;

/**
 * 
 * @author yemaoan
 *
 */
public class ContentServiceThread extends Thread {
    
    private static List<ContentService> list = new ArrayList<ContentService>();
    private String name;
    
    public ContentServiceThread(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for(int index = 0; index < 5; index++) {
            ContentService contentService = ContentService.contentServiceInstance();
            list.add(contentService);
            System.out.print(this.name + "  ");
        }
    }
    
    public static void main(String[] args) throws InterruptedException  {
        //啓動四線程,每線程生成5個ContentService
        //thread begin
        new ContentServiceThread("A").start();
        new ContentServiceThread("B").start();
        new ContentServiceThread("C").start();
        new ContentServiceThread("D").start();
        //thread end
        Thread.sleep(2000);
        System.out.println();
        System.out.println("當前對象總數爲:" + list.size());
        for(int index = 0; index < list.size(); index++) {
            System.out.println((index+1) + " : " + list.get(index));
        }
    }
}

  筆者用了四個線程,每一個線程生成5個ContentService對象,讓咱們看一下具體運行效果:

B  A  D  C  D  A  B  A  D  C  D  A  B  A  D  C  B  C  B  C  
當前對象總數爲:20
1 : com.pattern.stategy.factory.ContentService@1034bb5
2 : com.pattern.stategy.factory.ContentService@1034bb5
3 : com.pattern.stategy.factory.ContentService@1034bb5
4 : com.pattern.stategy.factory.ContentService@1034bb5
5 : com.pattern.stategy.factory.ContentService@1034bb5
6 : com.pattern.stategy.factory.ContentService@1034bb5
7 : com.pattern.stategy.factory.ContentService@1034bb5
8 : com.pattern.stategy.factory.ContentService@1034bb5
9 : com.pattern.stategy.factory.ContentService@1034bb5
10 : com.pattern.stategy.factory.ContentService@1034bb5
11 : com.pattern.stategy.factory.ContentService@1034bb5
12 : com.pattern.stategy.factory.ContentService@1034bb5
13 : com.pattern.stategy.factory.ContentService@1034bb5
14 : com.pattern.stategy.factory.ContentService@1034bb5
15 : com.pattern.stategy.factory.ContentService@1034bb5
16 : com.pattern.stategy.factory.ContentService@1034bb5
17 : com.pattern.stategy.factory.ContentService@1034bb5
18 : com.pattern.stategy.factory.ContentService@1034bb5
19 : com.pattern.stategy.factory.ContentService@1034bb5
20 : com.pattern.stategy.factory.ContentService@1034bb5

5、總結

  1. 單例在設計模式中是比較簡單的一個了,它是用途主要是保證一個類有且只有一個實例化對象。

  2. 單例在多線程中須要注意一下併發產生對象不一的狀況,這也許在壓力過程當中就能體現出來。

6、題外話

  在這裏就事論事地說一下,有人也許會認爲直接把一個對象設置成一個全局變量就得了,何須這麼糾結呢?呵呵,筆者認爲,一個全局變量畢竟是一開始就要初始化建立,耗資源吶,再說假若後期沒用了,怎麼辦,豈不是白白浪費了......而採用單例的話,那又不一樣說法了,畢竟單例是咱們須要的時候纔去建立,再者單例模式能夠確保一個對象只有被實例化一次。

相關文章
相關標籤/搜索