Java設計模式二:深入理解單例模式

前言

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。

這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。

這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

定義

單例模式: 一個類有且只有一個實例,且提供一個全局訪問方法來訪問這個實例。

注:1、被static修飾的變量成爲靜態變量,當類加載器將類加載到JVM中的時候就會創建靜態變量,這跟對象是否創建無關。

       2、靜態代碼塊:靜態代碼塊的代碼只會在類第一次初始化的時候執行一次。

       3、靜態變量創建後,會一直放在內存中,只有進程被殺掉時,纔會被清空。這也是單例模式的核心。

單利模式

1、餓漢模式

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

缺點是在類加載的時候就實例化了對象,有點浪費空間,優點是線程安全,因爲static變量會在類裝載的時候初始化,並且多個實例的static變量會共享一塊內存區域。

2、懶漢模式

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

但是由於線程不安全,於是加上了synchronized關鍵字修飾方法

public class Singleton{
        private static Singleton singleton= null;
        private Singleton(){
        }
        public synchronized Singleton getInstance(){
            if (singleton == null){
                singleton = new Singleton();
            }
            return singleton;
        }
}

加上鎖以後又影響性能,於是又有了雙鎖檢測(DCL)版本的單例模式(雙重檢查+鎖)

public class Singleton {
        private static volitile Singleton singleton = null;

        private Singleton() {
        }

        public Singleton getInstance() {
            if (singleton == null) {
                synchronized (this) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
}

1.爲什麼要進行第一次判空

如果說我們沒有第一次驗校,每一個線程都要走synchronized 中的代碼,而每一次線程都要去拿到同步鎖才能執行。在多線程的情況下每一個線程要拿到single 對象都要排隊等待同步鎖釋放。因此第一次驗校作用就是爲了提高程序的效率。

2.爲什麼要進行第二次判空

如果有兩個線程A和B都通過了第一次判空,進入到獲取鎖階段A拿到鎖進行對象創建後釋放鎖,此時B就不需要在創建對象,所以再次判斷不爲空,直接返回。

3.變量爲什麼要加volatile關鍵字

volatile防止指令重排序,single = new Single() 在我們看來就是一句話操作而已,但在虛擬機看來它一共分爲了幾個指令操作:

  • 爲對象分配內存空間
  • 初始化對象
  • 將引用指向對象的內存空間地址

假如線程A執行 single = new Single()虛擬機是按132排序執行,當執行到3的時候single 引用已經不爲空。此時若線程B執行到第一次驗校處(第一次驗校不在同步代碼中,因此所有線程隨時都可以訪問),它判斷 single ==null 得到false,直接返回single對象。但是此時single對象還沒初始化完成,因此很有可能就會發生bug。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章