單例模式-懶漢式(雙重檢驗)


上章節我們在懶漢式的單例模式上解決了多線程安全的問題,但解決問題的同時,新的問題也隨之而來。

上節問題:

1、在靜態方法(static)上添加關鍵字(synchronized同步鎖),就是相當於在類上加鎖,鎖的范圍大,損耗性能。

2、加鎖、解鎖過程消耗資源。

那么,我們該如何解決呢?

 1 public class lazyDoubleCheckSingleton {
 2 
 3   private static lazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
 4 
 5   private lazyDoubleCheckSingleton() {
 6 
 7   }
 8   public static lazyDoubleCheckSingleton getInstance() {
 9     if (lazyDoubleCheckSingleton == null) {
10       synchronized (lazyDoubleCheckSingleton.class){
11         if (lazyDoubleCheckSingleton == null){
12           lazyDoubleCheckSingleton = new lazyDoubleCheckSingleton();
//1、分配內存給這個對象
//2、初始化對象
//3、設置
lazyDoubleCheckSingleton,指向剛分配的內存地址
13  } 14  } 15  } 16 return lazyDoubleCheckSingleton; 17  } 18 }

此種方法就是懶漢模式的雙重檢測式,把鎖加在方法里面,只有空的話才會加鎖,不為空的話,直接return lazyDoubleCheckSingleton,大大節省了開銷,但是這段代碼,還存在着兩大隱患,分別是9行、12行,首先在9行判斷了是否為空,有可能是不為空的,他雖然不為空,但是是在12行還沒完成初始化的情況下,12行的代碼雖然是一行,確實經歷了三個步驟,注釋上2和3的順序可能調換,進行重排序,也就是先指向內存地址,但是還沒初始化對象。下面給大家開一個圖。

這是單線程,介入多線程呢?

看吧,就出問題了呢,想要解決這個問題,有兩種解決方案

1、不允許2、3進行重排序,加入了volatile關鍵字.
2、允許一個線程進行重排序,但不允許另外線程看到他的重排序。
那么我們看看用第一種方案是怎么解決的呢?
/**
 * Created by sww_6 on 2019/4/10.
 * 雙重檢查
 * 1、不允許2、3進行重排序,加入了volatile關鍵字.
 * 2、允許一個線程進行重排序,但不允許另外線程看到他的重排序。
 * 划重點:
 * 1、在多線程的時候,cpu有共享內存。
 * 2、加入了volatile關鍵字之后,所有線程都能看到共享內存的最新狀態,保證內存可見性。
 * <p>
 * 怎么保持內存一致性?
 * 用volatile修飾的共享變量,在進行寫操作的時候,會多出來很多匯編代碼,起到兩個作用。
 * 1、是將當前處理器緩存行的數據寫回到系統內存,寫回內存的操作,會使在其他cpu里緩存了該內存的數據無效,其他cpu緩存的數據無效了,就會從共享內存同步數據。保證了內存的可見性。
 * 主要使用的是緩存一致性協議
 * <p>
 * 優點:
 * 既兼顧了性能,又兼顧了線程安全。
 */
public class lazyDoubleCheckSingleton {

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

好了,我們下期見!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM