今天筆者想寫的設計模式——單例模式,其意圖就是爲了使系統有且僅有一個實例化,也就是一個對象我只有new一次就夠了,也是像咱們平凡人同樣,婚結一次就夠了,可是如今的社會啊,我只能以「理想很豐滿,現實很骨感」來形容了,讓咱們一塊兒瞭解下單例設計模式吧。java
1. 定義:它是比較簡單的一個模式,就是確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例。算法
2. 類圖:單純的單例模式,其實就一個類,因此在此處就省略一下類圖吧。數據庫
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; } }
單例看起來就是如上面的兩種狀況同樣,至關簡單,若是真的這麼認爲單例就這樣完了,那你可能真的可能完了。說不定哪一天你的婚姻真的因插入一個小三給毀了,固然,言重了,那讓咱們分析一下弊病吧。多線程
在大數據的背景下,併發處理就不可或缺了,而只是簡簡單單的單例就可能經不起壓力測試了,從源碼分析上,很容易就發如今問題所在了。怎麼解決了,暫且能夠在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
1. 單例在設計模式中是比較簡單的一個了,它是用途主要是保證一個類有且只有一個實例化對象。
2. 單例在多線程中須要注意一下併發產生對象不一的狀況,這也許在壓力過程當中就能體現出來。
在這裏就事論事地說一下,有人也許會認爲直接把一個對象設置成一個全局變量就得了,何須這麼糾結呢?呵呵,筆者認爲,一個全局變量畢竟是一開始就要初始化建立,耗資源吶,再說假若後期沒用了,怎麼辦,豈不是白白浪費了......而採用單例的話,那又不一樣說法了,畢竟單例是咱們須要的時候纔去建立,再者單例模式能夠確保一個對象只有被實例化一次。