最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java Volatile應(yīng)用單例模式實現(xiàn)過程解析

 更新時間:2020年11月04日 10:38:17   作者:柒  
這篇文章主要介紹了Java Volatile應(yīng)用單例模式實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

單例模式

回顧一下,單線程下的單例模式代碼

餓漢式

  • 構(gòu)造器私有化
  • 自行創(chuàng)建,并且用靜態(tài)變量保存static
  • 向外提供這個實例 public
  • 強調(diào)這是一個單例,用final
public class sington(){
  public final static INSTANCE = new singleton();
  private singleton(){}
}

第二種:jdk1.5之后用枚舉類型

枚舉類型:表示該類型的對象是有限的幾個

我們可以限定為1個,就稱了單例

public enum Singleto{
  INSTANCE
}

第三種靜態(tài)代碼塊

public class Singleton{
public final static INSTANCE;
static{
  INSTANCE = new Singleton();
}
private Singleton(){}

}

懶漢式構(gòu)造器私有化

用一個靜態(tài)變量保存這個唯一實例

提供一個靜態(tài)方法,獲取這個實例

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

  private static SingletonDemo instance = null;

  private SingletonDemo () {
    System.out.println(Thread.currentThread().getName() + "\t 我是構(gòu)造方法SingletonDemo");
  }

  public static SingletonDemo getInstance() {
    if(instance == null) {
      instance = new SingletonDemo();
    }
    return instance;
  }

  public static void main(String[] args) {
    // 這里的 == 是比較內(nèi)存地址
    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
  }
}

最后輸出結(jié)果:


但是在多線程的環(huán)境下,我們的單例模式是否還是同一個對象了

public class SingletonDemo {

  private static SingletonDemo instance = null;

  private SingletonDemo () {
    System.out.println(Thread.currentThread().getName() + "\t 我是構(gòu)造方法SingletonDemo");
  }

  public static SingletonDemo getInstance() {
    if(instance == null) {
      instance = new SingletonDemo();
    }
    return instance;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
      new Thread(() -> {
        SingletonDemo.getInstance();
      }, String.valueOf(i)).start();
    }
  }
}

從下面的結(jié)果我們可以看出,我們通過SingletonDemo.getInstance() 獲取到的對象,并不是同一個,而是被下面幾個線程都進行了創(chuàng)建,那么在多線程環(huán)境下,單例模式如何保證呢?

解決方法一

引入synchronized關(guān)鍵字

public synchronized static SingletonDemo getInstance() {
  if(instance == null) {
    instance = new SingletonDemo();
  }
  return instance;
}

輸出結(jié)果:


我們能夠發(fā)現(xiàn),通過引入Synchronized關(guān)鍵字,能夠解決高并發(fā)環(huán)境下的單例模式問題

但是synchronized屬于重量級的同步機制,它只允許一個線程同時訪問獲取實例的方法,但是為了保證數(shù)據(jù)一致性,而減低了并發(fā)性,因此采用的比較少

解決方法二

通過引入DCL Double Check Lock雙端檢鎖機制

  public static SingletonDemo getInstance() {
    if(instance == null) {
      // 同步代碼段的時候,進行檢測
      synchronized (SingletonDemo.class) {
        if(instance == null) {
          instance = new SingletonDemo();
        }
      }
    }
    return instance;
  }

最后輸出的結(jié)果為:

從輸出結(jié)果來看,確實能夠保證單例模式的正確性,但是上面的方法還是存在問題的

DCL(雙端檢鎖)機制不一定是線程安全的,原因是有指令重排的存在,加入volatile可以禁止指令重排

原因是在某一個線程執(zhí)行到第一次檢測的時候,讀取到 instance 不為null,instance的引用對象可能沒有完成實例化。因為 instance = new SingletonDemo();可以分為以下三步進行完成:

  • memory = allocate(); // 1、分配對象內(nèi)存空間
  • instance(memory); // 2、初始化對象
  • instance = memory; // 3、設(shè)置instance指向剛剛分配的內(nèi)存地址,此時instance != null

但是我們通過上面的三個步驟,能夠發(fā)現(xiàn),步驟2 和 步驟3之間不存在 數(shù)據(jù)依賴關(guān)系,而且無論重排前 還是重排后,程序的執(zhí)行結(jié)果在單線程中并沒有改變,因此這種重排優(yōu)化是允許的。

  • memory = allocate(); // 1、分配對象內(nèi)存空間
  • instance = memory; // 3、設(shè)置instance指向剛剛分配的內(nèi)存地址,此時instance != null,但是對象還沒有初始化完成
  • instance(memory); // 2、初始化對象

這樣就會造成什么問題呢?

也就是當(dāng)我們執(zhí)行到重排后的步驟2,試圖獲取instance的時候,會得到null,因為對象的初始化還沒有完成,而是在重排后的步驟3才完成,因此執(zhí)行單例模式的代碼時候,就會重新在創(chuàng)建一個instance實例

指令重排只會保證串行語義的執(zhí)行一致性(單線程),但并不會關(guān)系多線程間的語義一致性

所以當(dāng)一條線程訪問instance不為null時,由于instance實例未必已初始化完成,這就造成了線程安全的問題

所以需要引入volatile,來保證出現(xiàn)指令重排的問題,從而保證單例模式的線程安全性

private static volatile SingletonDemo instance = null;

最終代碼

public class SingletonDemo {

  private static volatile SingletonDemo instance = null;

  private SingletonDemo () {
    System.out.println(Thread.currentThread().getName() + "\t 我是構(gòu)造方法SingletonDemo");
  }

  public static SingletonDemo getInstance() {
    if(instance == null) {
      // a 雙重檢查加鎖多線程情況下會出現(xiàn)某個線程雖然這里已經(jīng)為空,但是另外一個線程已經(jīng)執(zhí)行到d處
      synchronized (SingletonDemo.class) //b
      { 
      //c不加volitale關(guān)鍵字的話有可能會出現(xiàn)尚未完全初始化就獲取到的情況。原因是內(nèi)存模型允許無序?qū)懭?
        if(instance == null) { 
        	// d 此時才開始初始化
          instance = new SingletonDemo();
        }
      }
    }
    return instance;
  }

  public static void main(String[] args) {
//    // 這里的 == 是比較內(nèi)存地址
//    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//    System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());

    for (int i = 0; i < 10; i++) {
      new Thread(() -> {
        SingletonDemo.getInstance();
      }, String.valueOf(i)).start();
    }
  }
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring mvc實現(xiàn)登錄賬號單瀏覽器登錄

    spring mvc實現(xiàn)登錄賬號單瀏覽器登錄

    這篇文章主要為大家詳細介紹了spring mvc實現(xiàn)登錄賬號單瀏覽器登錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java反射中java.beans包學(xué)習(xí)總結(jié)

    Java反射中java.beans包學(xué)習(xí)總結(jié)

    本篇文章通過學(xué)習(xí)Java反射中java.beans包,吧知識點做了總結(jié),并把相關(guān)內(nèi)容做了關(guān)聯(lián),對此有需要的朋友可以學(xué)習(xí)參考下。
    2018-02-02
  • java工具類SendEmailUtil實現(xiàn)發(fā)送郵件

    java工具類SendEmailUtil實現(xiàn)發(fā)送郵件

    這篇文章主要為大家詳細介紹了java工具類SendEmailUtil實現(xiàn)發(fā)送郵件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Java使用StampedLock實現(xiàn)高效讀寫功能

    Java使用StampedLock實現(xiàn)高效讀寫功能

    StampedLock 是 Java 8 引入的高性能鎖,提供了三種鎖模式:寫鎖、悲觀讀鎖和樂觀讀鎖,與傳統(tǒng)的 ReentrantReadWriteLock 相比,StampedLock 更注重性能,特別適合讀多寫少的場景,所以本文給大家介紹了Java使用StampedLock實現(xiàn)高效讀寫功能,需要的朋友可以參考下
    2025-01-01
  • 關(guān)于Java中的try-with-resources語句

    關(guān)于Java中的try-with-resources語句

    這篇文章主要介紹了關(guān)于Java中的try-with-resources語句,try-with-resources是Java中的環(huán)繞語句之一,旨在減輕開發(fā)人員釋放try塊中使用的資源的義務(wù),需要的朋友可以參考下
    2023-05-05
  • 使用itextpdf操作pdf的實例講解

    使用itextpdf操作pdf的實例講解

    下面小編就為大家分享一篇使用itextpdf操作pdf的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Centos中安裝jdk案例講解

    Centos中安裝jdk案例講解

    這篇文章主要介紹了Centos中安裝jdk案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 如何解決Spring的UnsatisfiedDependencyException異常問題

    如何解決Spring的UnsatisfiedDependencyException異常問題

    這篇文章主要介紹了如何解決Spring的UnsatisfiedDependencyException異常問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Java多線程模擬銀行系統(tǒng)存錢問題詳解

    Java多線程模擬銀行系統(tǒng)存錢問題詳解

    本文將利用Java多線程模擬一個簡單的銀行系統(tǒng),使用兩個不同的線程向同一個賬戶存錢。文中的示例代碼講解詳細,感興趣的可以了解一下
    2022-09-09
  • springmvc整合freemarker配置的詳細步驟

    springmvc整合freemarker配置的詳細步驟

    本篇文章主要介紹了springmvc整合freemarker的詳細步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05

最新評論

亳州市| 怀化市| 太康县| 葵青区| 琼结县| 临武县| 湖南省| 重庆市| 高清| 桓仁| 视频| 马鞍山市| 贡觉县| 徐水县| 镶黄旗| 博湖县| 上虞市| 漯河市| 中超| 临西县| 汝阳县| 公安县| 金门县| 五原县| 汤阴县| 汉阴县| 广元市| 东乌| 色达县| 固阳县| 安新县| 桐梓县| 祁阳县| 辉南县| 长寿区| 临湘市| 张家港市| 同江市| 大同市| 沈阳市| 祥云县|