您好,登錄后才能下訂單哦!
這篇文章主要介紹“java單例模式實例分析”,在日常操作中,相信很多人在java單例模式實例分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java單例模式實例分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在早期的項目代碼中,如果我們想使用類的某個方法,我們基本都會創建一個類的對象實例然后再調用方法,這樣的實現往往在系統內就會存在某個類的大量實例。如此一來,項目框架很難管理大量的對象,而且如果java虛擬機不能及時回收,容易造成內存溢出。
首先我們要明白什么是單例,所謂單例就是說在項目框架內某個類的對象實例只存在一個,任何調用方獲取到的對象實例都是一個,那么很明顯這個類是不能夠被外部直接調用類構造器創建的。
我們先看下一個簡單的單例設計:
上面代碼在單線程是沒有問題的,而且只有當線程調用類的靜態方法時,才會生成類的靜態變量。但是當多線程訪問時,上面代碼是有問題的,會生成多個對象的實例。
那么,我們可以用另外一種方法實現,比如說在類加載時候就初始化對象的實例,這樣后面無論怎么調用類靜態方法都不創建新的實例。還有一種方法,但是會犧牲部分系統性能,意思就是在多線程訪問方法時通過鎖機制讓線程排隊訪問。我們先通過在類方法上加鎖來實現類的單例,比如:
上述方法能實現單例,而且采用的思路是延遲加載,但是執行效率比較低。
之前有看到部分同學使用雙重鎖(Double CheckLock)機制來實現單例模式,一方面需要在實例上加上volatile關鍵字通知操作系統實現線程訪問時內存屏障,然后還需要在方法中通過虛擬機實現的synchronized來同步方法訪問,寫法如下:
反正,我認為上面的實現是比較復雜的,大家需要去了解的知識點比較多,比如volatile ,synchronized,內存屏障。因此我不建議大家用這種方式,可以作為技術了解下還是有好處的,畢竟如果能跟面試官探討到這一步,還是會加一些分的。
如果說我們不考慮服務負載問題,在多線程環境下可以預先加載類的靜態實例,當虛擬機加載完成類后就會創建類的靜態變量,甭管你到時用不用,反正給你留在那里。所有線程訪問到的都是同一靜態實例,有人也稱這種方式為餓漢式,具體寫法如下:
上面寫法實現單例也是沒有問題的,但是有些同學就會覺得如果我只是想調用一個類的某個靜態方法,并不想生成它的實例,那有沒有其他方法呢,經過各路大神的指點結合自身的總結,可以使用內部靜態類來實現這個需求。
開發的同學都知道,虛擬機在加載類的過程中一開始并不會初始化類的內部靜態類。如果線程調用內部靜態類時,虛擬機只會初始化一次,這樣既可以實現單例,同時也是線程安全的。具體寫法如下:
除了以上講到的幾種方式外,JDK自身的枚舉類型本身就是單例的實現,調用者不能顯式的調用構造器完成實例創建,因此很多Java規范文檔推薦使用枚舉來實現單例。
當然對于初級開發人員而言,現在的主流開發框架都提供單例/多例模式供開發者選擇,這樣的好處讓開發者更多關注業務功能開發,而不用過多關注虛擬機內部類實例創建問題。例如spring中默認類注入就是單例的,可以根據實際情況設置scope為singleton(單例)或者prototype(多例),如下圖所示:
到此,關于“java單例模式實例分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。