1. 程式人生 > >單例設計模式的設計——Double-Check

單例設計模式的設計——Double-Check

package SingleInstanceModel;

import java.net.Socket;
import java.sql.Connection;

/**
 * Created by JYM on 2019/1/8
 * 單例模式:Double-Check
 * Double-Check是一種比較聰明的設計方式,他提供了一種高效的資料同步策略,那就是首次初始化時加鎖,之後則允許多個執行緒同時
 * 進行getInstance方法的呼叫來獲得類的例項。
 * */

//final不允許被繼承
public final class Singleton_3
{
    //例項變數
    private byte[] data = new byte[1024];

    private static Singleton_3 instance = null;

    Connection connection;
    Socket socket;

    private Singleton_3()
    {
        this.connection   //初始化connection
        this.socket    //初始化socket
    }

    public static Singleton_3 getInstance()
    {
        //當instance為null時,進入同步程式碼塊,同時該判斷避免了每次都需要進入同步程式碼塊,可以提高效率
        if (null == instance)
        {
            //只有一個執行緒能夠獲得Singleton.class關聯的monitor
            synchronized (Singleton_3.class)
            {
                //判斷如果instance為null則建立
                if (null==instance)
                {
                    instance = new Singleton_3();
                }
            }
        }
        return instance;
    }
}

/**
 * 當兩個執行緒發現null==instance成立時,只有一個執行緒有資格進入同步程式碼塊,完成對instance的例項化,隨後的執行緒發現null==instance不成立
 * 則無須進行任何動作,以後對getInstance的訪問就不需要資料同步的保護了。
 * 這種方式看起來是那麼的完美和巧妙,既滿足了懶載入,又保證了instance例項的唯一性,Double-Check的方式提供了高效的資料同步策略,可以允許多個執行緒
 * 同時對getInstance進行訪問,但是這種方式在多執行緒的情況下有可能會引起空指標異常。
 * 分析一下產生異常的原因:
 * 在Singleton的建構函式中,需要分別例項化conn和socket兩個資源,還有Singleton_3自身,根據 JVM執行時指令重排序和Happens_Before規則,這三者之間
 * 的例項化順序並無前後關係的約束,那麼極有可能是instance最先被例項化,而conn和socket並未完成例項化,未完成初始化的例項呼叫其方法將會丟擲空指標
 * 異常。*/