日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

单例模式到Java内存模型

發布時間:2023/12/19 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单例模式到Java内存模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先說單例模式:

經典的單例模式實現:

餓漢式:

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

懶漢式:

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

這兩種都是可以安全運行在多線程下的。但是每一個都有點缺點,對于第一種如果這個單例的初始化需要很多內存和時間,我們希望用到時在初始化,沒有用到就不初始化。對于第二種我們,其實只需要在第一次初始化時需要避免線程沖突,其他時候都可以直接返回的,而第二種的實現則變成了完全的串行(因為每一個操作都需要獲得對象鎖),非常大的降低了并發度。

我們嘗試以下改進:

一個好的方式是DCL(double-checked?locking),這種方式的實現如下:

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

這樣看起來是完美的解決方案,確實DCL是一個很好的解決思想,在C下其能很好的運行,但在Java下就會有問題了。這全怪Java的JMM(Java內存模型)。

在執行到instance = new Singleton()這里時,由于Java內存的“無序寫入”,

可能的執行順序是這樣的:

mem?=?allocate();?????????????//Allocate?memory?for?Singleton?object.
?instance?=?mem;???????????????//Note?that?instance?is?now?non-null,?but?has?not?been?initialized.
?ctorSingleton(instance);??????//Invoke?constructor?for?Singleton?passinginstance.

即為instance分配內存,標記instance不為空,初始化instance。

這樣會導致,一個線程剛標記完,還沒有初始化賦值給instance,就釋放了鎖,然后另一個線程進入鎖,判斷不為空,釋放鎖,返回instance,這時顯然是錯的。這里出現這中錯誤的原因是instance = new instance();并沒有真正的執行完,就釋放了鎖,我實在不能理解這樣設計的原因,但很好的是在JDK1.5之后,已不存在這種問題了DCL這個可以很好的運行。但我們還是有必要繼續討論JDK1.5之前如何實現的。

可以在instance返回之前加一個步奏,確定其確實初始化了。

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

這樣就很好的解決這個問題了。但是代碼量和可閱讀性已經陡然上升了,那么有沒有更好的方法呢?是有的,利用類加載機制來實現,延遲初始化。

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

這里補充一點類加載的知識,類加載分為一個步驟,加載->驗證->準備->解析->初始化->使用->卸載。

Java中對何時初始化一個類有嚴格的說明,這里涉及到的一個規則是當類的靜態域,或靜態方法被引用的時候,必須對聲明這個靜態域或方法的類進行初始化。至于說明時候對類進行加載,這個有兩種形式:餓加載(只要有其他類引用了它就加載),懶加載(初始化的時候才加載)。具體JVM對這點的實現不同。

所以當懶漢式能保證用到的時候才進行初始化,而餓漢試則是在加載時就初始化了。

?

轉載于:https://www.cnblogs.com/chaiwentao/p/4959648.html

總結

以上是生活随笔為你收集整理的单例模式到Java内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。