懶漢式單例模式爲什麼要進行二次判空

最困難的事情就是認識自己!

個人博客,歡迎訪問!

前言:

            在本文中會使用代碼進行展示懶漢單例模式爲什麼需要進行二次判空;代碼中使用到 CountDownLatch 倒計時器,不清楚CountDownLatch 使用的請參考此文https://www.jianshu.com/p/f17692e9114f 。

 

代碼展示:

1、懶漢式單例模式類

public class Singleton {
	
	    // 使用volatile禁止指令重排序
		private static volatile Singleton sin = null;

	    public static int i = 0;// 標識有幾個線程獲取到了鎖
	    public static int j = 0;// 標識系統中到底生成了幾個實例

		// 將構造器的修飾符設置爲"private",可以防止在外部進行new實例對象
		private Singleton() {
		};

		// 獲取實例對象的方法,公共的方法。
		public static Singleton getInstance() {
			// 第一次判空。
			if (sin == null) {
				// 加鎖
				synchronized (Singleton.class) {
					i++;
					// 第二次判空。
					if (sin == null) {
						sin = new Singleton();
						j++;
					}
				}
			}
			return sin;
		}
}

2、多線程併發調用單例模式的測試類

public class ThreadTest implements Runnable  {
	
	//實例化一個倒計樹器,初始倒計數爲10
	static final CountDownLatch latch = new CountDownLatch(10);
	static final ThreadTest demo = new ThreadTest();

	@Override
	public void run() {
		try {
			//實例對象生成
			Singleton.getInstance();
			//輸出當前線程的名稱
			System.out.println(Thread.currentThread().getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			//計數器進行減一
			latch.countDown();
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		//創建一個長度爲10的定長線程池
		ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i=0; i<10; i++){
        	//啓動線程
            exec.submit(demo);
        }
        
        //等待檢查,阻塞main主線程,只有當CountDownLatch倒計數器爲0時纔會喚醒阻塞的main主線程
        latch.await();  
        
        // 開啓的10個線程中幾個線程獲取到了鎖
		System.out.println("共有 ( " + Singleton.i + " ) 個線程獲取到對象鎖");
		// 最終生成了幾個Singleton實例
		System.out.println("最終生成了( " + Singleton.j + " )個Singleton實例對象");
        
        // 關閉線程池
        exec.shutdown();
	}
}

 運行上面的mian方法,會得到以下的一種輸出結果(存在多種輸出結果):

pool-1-thread-1
pool-1-thread-7
pool-1-thread-5
pool-1-thread-3
pool-1-thread-6
pool-1-thread-2
pool-1-thread-4
pool-1-thread-9
pool-1-thread-8
pool-1-thread-10
共有 ( 2 ) 個線程獲取到對象鎖
最終生成了( 1 )個Singleton實例對象

總結:

        從運行結果可以看出,如果不進行第二次判空的話,那麼在竟鎖池(鎖池)中如果還有活躍的線程在等待獲取的鎖的話,在鎖釋放後就會再次競爭獲取鎖,獲取的鎖的線程進入"就緒狀態",當cpu分配其"時間片"後進行線程的調度,從而線程進入"運行中狀態",並會去執行同步的代碼塊,如果在沒加如二次判空的話,就會導致系統中存在多個實例,而在進行判空後,即使你獲取到了鎖,但在執行同步代碼塊時也會直接跳過。

       竟鎖池(鎖池)的概念:https://blog.csdn.net/qq_22498277/article/details/82184419

 

不要忘記留下你學習的足跡 [點贊 + 收藏 + 評論]嘿嘿ヾ

一切看文章不點贊都是“耍流氓”,嘿嘿ヾ(◍°∇°◍)ノ゙!開個玩笑,動一動你的小手,點贊就完事了,你每個人出一份力量(點贊 + 評論)就會讓更多的學習者加入進來!非常感謝! ̄ω ̄=

發佈了22 篇原創文章 · 獲贊 33 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章