对Java单例模式 volatile关键字作用的理解
單例模式是程序設(shè)計中經(jīng)常用到的,簡單便捷的設(shè)計模式,也是很多程序猿對設(shè)計模式入門的第一節(jié)課。其中最經(jīng)典的一種寫法是:
class Singleton {private volatile static Singleton instance;//volatile關(guān)鍵字防止指令重排private Singleton(){}public static Singleton getInstance() {if ( instance == null ) { //一重判斷synchronized (Singleton.class) {//對Singleton.class上鎖if ( instance == null ) {//二重判斷instance = new Singleton();}}}return instance;} }其中有兩個關(guān)鍵的地方:1,初始化instance實例的時候,采用兩重判斷對Singleton.class上鎖。
2,靜態(tài)變量instance使用了volatile關(guān)鍵字進行修飾。
第一個問題相對比較好理解
if ( instance == null ) { //一重判斷synchronized (Singleton.class) {//對Singleton.class上鎖if ( instance == null ) {//二重判斷instance = new Singleton();}}}
sychronized關(guān)鍵字鎖住Singleton類而不是instance對象,是因為,此時instance為空,加sychronized沒有意義。
第一重判斷的意義在于:如果instance非空,就跳過了鎖的步驟,減少加鎖的資源開銷。但是由于第一重判斷在代碼鎖之外,如果不同線程同時訪問到install==null,會先后阻塞執(zhí)行代碼鎖內(nèi)的內(nèi)容。所以在代碼鎖內(nèi)加第二重判斷就很有必要了,避免第一個線程獲取實例后,第二個線程獲得資源鎖又執(zhí)行了一次instance的初始化,產(chǎn)生兩個不同的實例。
很多人不理解instance實例在聲明時加volatile關(guān)鍵字的作用,或者是發(fā)現(xiàn)別人這么寫了,自己也跟著這么寫。對volatile關(guān)鍵字的解釋,很多地方只是提了句“當要求使用volatile 聲明的變量的值的時候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),它可以防止指令重排”,這里不想對這句話進行展開解釋,想詳細了解可以參考文章
https://www.cnblogs.com/shan1393/p/8999683.html
https://www.cnblogs.com/xrq730/p/7048693.html
instance = new Singleton()看上去只有一句話,但java的初始化成員變量包括內(nèi)存分配、初始化、返回對象在堆上的引用等一系列操作。對于synchronized代碼塊內(nèi),一條語句完整執(zhí)行是沒有問題的。但如果發(fā)生了指令重排,先返回對象在堆上的引用,再進行初始化。對于另一個執(zhí)行到一重判斷的線程來說,由于instance已經(jīng)指向了堆上的一段內(nèi)存空間,那么instance就不為空,會將未完成初始化的對象返回給其他函數(shù)調(diào)用,引發(fā)一系列不安全隱患。加了volatile關(guān)鍵字,可以保證返回對象在對上的引用發(fā)生在初始化之后,避免了這種情況的發(fā)生。這就是單例模式下 instance加volatile關(guān)鍵字的作用。
轉(zhuǎn)載于:https://www.cnblogs.com/acesui/p/9557501.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的对Java单例模式 volatile关键字作用的理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rabbitmqctl status报错
- 下一篇: php调用以太坊geth API说明