單例設計模式的設計——Double-Check
阿新 • • 發佈:2019-01-09
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並未完成例項化,未完成初始化的例項呼叫其方法將會丟擲空指標 * 異常。*/