中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中如何實現單例模式

發布時間:2021-06-12 19:07:45 來源:億速云 閱讀:193 作者:Leah 欄目:編程語言

這篇文章將為大家詳細講解有關Java中如何實現單例模式,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

單例模式的特點

  1. 一個類只允許產生一個實例化對象。

  2. 單例類構造方法私有化,不允許外部創建對象。

  3. 單例類向外提供靜態方法,調用方法返回內部創建的實例化對象。

 懶漢式(線程不安全)

其主要表現在單例類在外部需要創建實例化對象時再進行實例化,進而達到Lazy Loading 的效果。

通過靜態方法 getSingleton() 和private 權限構造方法為創建一個實例化對象提供唯一的途徑。

不足:未考慮到多線程的情況下可能會存在多個訪問者同時訪問,發生構造出多個對象的問題,所以在多線程下不可用這種方法。

/**
 * @author MrRoot
 * @since 2018-12-17
 * 懶漢式(線程不安全)
 */
public class Singleton {
  private static Singleton singleton;

  private Singleton(){

  }

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

懶漢式(線程安全,同步方法,不推薦使用)

針對懶漢式的線程不安全,自然會想到給 getSingleton() 進行 synchronized 加鎖來保證線程同步。

不足:效率低。大多數情況下這個鎖占用的額外資源都浪費了,每個線程在想獲得類的實例時候,執行 getSingleton() 方法都要進行同步。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 懶漢式(線程安全,同步方法,不推薦使用)
 */
public class Singleton {
  private static Singleton singleton;

  private Singleton(){

  }

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

}

餓漢式(線程安全)

在進行類加載時完成實例化對象的過程就是餓漢式的形式。

避免了線程同步問題,在運行這個類的時候進行加載,之后直接訪問

不足:相比接下來的靜態內部類而言,這種方法比靜態內部類多了內存常駐,容易造成內存浪費,也未達到延遲加載的效果。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 餓漢式(線程安全)
 */
public class Singleton{
  private static Singleton singleton = new Singleton();

  private Singleton(){

  }

  public static Singleton singleton(){
    return singleton;
  }
}

靜態內部類加載(線程安全)

靜態內部類不會在單例加載時加載,當調用 getSingleton() 方法時才會進行加載,達到類似懶漢式效果,并且也是線程安全的。

類的靜態屬性只會在第一次加載類時進行初始化,所以上面的方法JVM 幫助我們保證了線程的安全性,在類進行初始化時,其他線程無法進入。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 靜態內部類加載(線程安全)
 */
public class Singleton{
  private static Singleton singleton;

  private static class SingletonInner{
    private static final Singleton instance = new Singleton();
  }

  public static Singleton getSingleton(){
    return SingletonInner.instance;
  }
}

枚舉(線程安全)

自由串行化;保證只有一個實例;線程安全。

Effective Java 作者所提倡的方法,近乎完美,在繼承場景下不適用。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 枚舉(線程安全)
 */
enum Singleton{
  INSTANCE;

  public void method(){

  }
}

class Test{
  public static void main(String[] args) {
    Singleton.INSTANCE.method();
  }
}

懶漢式雙重校驗鎖法(通常線程安全,不可保證完全安全)

使用同步代碼塊避免了第二種方法的效率低的問題,但此方法并不能完全起到線程同步的作用,與上面第一種方法產生的問題相似,多線程訪問時可能產生多個對象。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 懶漢式雙重校驗鎖法(通常線程安全,不可保證完全安全)
 */
class Singleton{
  private static Singleton singleton;

  private Singleton(){

  }

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

懶漢式雙重檢查終極版

與第六種方法不同的是,此方法給singleton 的聲明上加了關鍵字 volatile ,進而解決了低概率的線程不安全問題。

volatile 起到禁止指令重排的作用,在它賦值完成之前,就不會調用讀操作(singleton == null)。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 懶漢式雙重檢查終極版(volatile)
 */
class Singleton{
  private static volatile Singleton singleton;

  private Singleton(){

  }

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

使用 ThreadLocal 實現(線程安全)

ThreadLocal 會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。

對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal 采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

/**
 * @author MrRoot
 * @since 2019-3-27
 * 使用 ThreadLocal 實現(線程安全)
 */
class Singleton{
  private static final ThreadLocal<Singleton> singleton = new
      ThreadLocal<Singleton>(){
        @Override
        protected Singleton initialValue(){
          return new Singleton();
        }
      };

  private Singleton(){

  }

  public static Singleton getSingleton(){
    return singleton.get();
  }
}

使用CAS 鎖實現(線程安全)

/**
 * @author MrRoot
 * @since 2019-3-27
 * 使用 CAS 實現(線程安全)
 */
public class Singleton {
  private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

  private Singleton(){

  }

  public static final Singleton getSingleton(){
    for (;;){
      Singleton current = INSTANCE.get();
      if (current != null){
        return current;
      }
      current = new Singleton();
      if (INSTANCE.compareAndSet(null,current)){
        return current;
      }
    }
  }

  public static void main(String[] args) {
    Singleton singleton1 = Singleton.getSingleton();
    Singleton singleton2 = Singleton.getSingleton();
    System.out.println(singleton1 == singleton2);
  }
}

關于Java中如何實現單例模式就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东山县| 惠来县| 珲春市| 大港区| 瑞安市| 涟水县| 萝北县| 泰来县| 大兴区| 深泽县| 察隅县| 错那县| 宁都县| 邳州市| 五台县| 泽库县| 乳山市| 凤山市| 大同市| 孝昌县| 台山市| 万年县| 玉林市| 贵港市| 钦州市| 奉化市| 静乐县| 哈密市| 威宁| 得荣县| 沙雅县| 蓝田县| 陕西省| 成都市| 厦门市| 九龙城区| 富平县| 兴化市| 静宁县| 商水县| 台江县|