設計模式-單列模式及原型模式

簡介: 單例模式是很是經典的高頻面試題,文章主要闡述單例模式的應用場景、IDEA 環境下的多線程調試方式、保證線程安全的單例模式策略、反射暴力攻擊單例解決方案及原理分析、序列化破壞單例的原理及解決方案、常見的單例模式寫法等方面來全面的解析單列模式的細節。java

1. 單列模式

1.1 單列模式定義

  • 單例模式(Singleton Pattern)是指確保一個類在任何狀況下都絕對只有一個實例,並提供一個全局訪問點
  • 隱藏其全部的構造方法
  • 單例模式是建立型模式

1.2 適用場景

  • 確保任何狀況下都絕對只有一個實例
  • ServletContext 、ServletContextConfig 等;在Spring 框架應用中ApplicationContext;數據庫的鏈接池也都是單例形式。

1.3 單例模式常見的寫法

單例模式主要包含如下幾種寫法:面試

  • 餓漢式單例
  • 懶漢式單例
  • 註冊式單例
  • ThreadLocal單例

餓漢式單例

餓漢式單例是在類加載時候就馬上初始化,而且建立單例對象,有着絕對的線程安全性,由於在線程還未出現以前就已經被建立了,因此不存在訪問線程安全性 數據庫

優勢:安全

  • 沒有加任何的鎖、執行效率比較高,在用戶體驗上來講,比懶漢式更好

缺點:微信

  • 類加載的時候就初始化,無論用與不用都佔着空間,浪費了內存

代碼實現:多線程

public class HungrySingleton {

    private HungrySingleton(){

    }

    private static HungrySingleton hungrySingleton = new HungrySingleton();

    public static HungrySingleton getHungrySingleton() {
        return hungrySingleton; 

    }

}

咱們也能夠採用靜態代碼塊來實現:框架

public class HungryStaticSingleton {

    private static final HungryStaticSingleton hungryStaticSingleton;

    static {
        hungryStaticSingleton = new HungryStaticSingleton(); 

    }

    private HungryStaticSingleton(){

    }

    public static HungryStaticSingleton getHungryStaticSingleton() {
        return hungryStaticSingleton; 

    }

}
上述兩種寫法都很是簡單,餓漢式適用的場景通常是單例對象比較少的狀況,在這基礎上咱們下面看一下性能更優的寫法。

懶漢式單例

被外部類調用的時候內部類纔會加載,會出現線程安全問題 性能

代碼實現: 測試

實現單例類 LazySimpleSingleton編碼

public class LazySimpleSingleton {

    private LazySimpleSingleton(){}

    private static LazySimpleSingleton lazySimpleSingleton = null;

    public static LazySimpleSingleton getLazySimpleSingleton() {
        if (lazySimpleSingleton == null){
            lazySimpleSingleton = new LazySimpleSingleton(); 
        }
        return lazySimpleSingleton; 

    }

}

咱們編寫線程測試類:

public class LazySimpleSingletonTest {

    public static void main(String[] args) {
        new Thread(()->{
            LazySimpleSingleton lazySimpleSingleton = LazySimpleSingleton.getLazySimpleSingleton(); 
            System.out.println(lazySimpleSingleton); 
        }).start(); 
        new Thread(()->{
            LazySimpleSingleton lazySimpleSingleton = LazySimpleSingleton.getLazySimpleSingleton(); 
            System.out.println(lazySimpleSingleton); 
        }).start(); 

    }

}

正常狀況下輸出的兩個對象是相同的,也是單例, 可是會存在輸出不一樣的狀況,也就是說出現線程安全問題,這裏咱們用 IDEA 的調試功能來進一步的詳細看看各個線程的執行狀況

用線程模式調試,手動控制線程的執行順序來跟蹤內存的變化狀態。先給線程內容打上斷點:

線程內部打斷點

線程0斷點進入

線程0進入內部方法

切換線程1斷點

線程1方法內部

線程1內部從新構建初始化

線程1從新構建初始化

兩個線程返回的內容

本文由AnonyStar 發佈,可轉載但需聲明原文出處。
仰慕「優雅編碼的藝術」 堅信熟能生巧,努力改變人生
歡迎關注微信公帳號 :coder簡碼 獲取更多優質文章
更多文章關注筆者博客 : IT簡碼
相關文章
相關標籤/搜索