程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> JAVA單例模式的實踐,JAVA模式實踐

JAVA單例模式的實踐,JAVA模式實踐

編輯:JAVA綜合教程

JAVA單例模式的實踐,JAVA模式實踐


單例模式是JAVA設計模式中最常用、最重要的設計模式之一。

最簡單的寫法是:

public class TestSingleton {

    private static String ourInstance = null;
    //私有化構造器
    private TestSingleton() {
    }
    //提供靜態方法給外部訪問
    public static String getOurInstance(){
        if(ourInstance == null){
              ourInstance="單例模式賦值成功!!!";
              System.out.print(ourInstance);
        }

        return ourInstance;
    }
}

這種寫法的單例模式是線程不安全的,下面用代碼來模擬一下多線程並發,代碼的執行情況:

public class Test {

    /**
     * 線程池
     */
   final static ExecutorService threadPool = Executors.newCachedThreadPool();

    /**
     * 並發數
     */
   private final static int CONCURRENT_COUNT = 10;
    /**
     *信號量
     */
   final static CountDownLatch locks = new CountDownLatch(CONCURRENT_COUNT);

   public static void main(String[] args) {

        for (int i = 0; i < CONCURRENT_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    locks.countDown();
                    TestSinleton.getOurInstance();
                }
            } );
        }
     locks.await(); } }

代碼非常簡單,用線程池執行CONCURRENT_COUNT 個任務,每個任務執行到

locks.countDown()

時被阻塞,當被阻塞的任務數達到CONCURRENT_COUNT個時,所有任務同時往下執行,這樣模擬了多個用戶並發的場景。(CountDownLatch 的使用方法)

思考:如果以上寫法的單例模式線程安全,那麼控制台只會打印一次:單例模式賦值成功!!!

運行3次程序,查看控制台輸出:

"C:\Program Files\Java\jdk1.8.0_101\bin\java" ...
單例模式復制成功!!!單例模式復制成功!!!
Process finished with exit code 0
"C:\Program Files\Java\jdk1.8.0_101\bin\java" ...
單例模式賦值成功!!!單例模式賦值成功!!!單例模式賦值成功!!!
Process finished with exit code 1
"C:\Program Files\Java\jdk1.8.0_101\bin\java"...
單例模式賦值成功!!!
Process finished with exit code 1

發現並不是想的這樣,很容易就出現了變量被多次賦值的情況。所以,以上的單例模式是線程不安全的。

思考為什麼會出現這種情況?

因為多用戶並發操作的情況下,if(ourInstance == null) 可能被同時執行,如果ourInstance為空的話,就會出現多個線程判斷(ourInstance == null)為true了。

修改代碼:

public class TestSinleton {

    private static String ourInstance = null;

    //私有化構造器
    private TestSinleton() {
    }
    //提供靜態方法給外部訪問
    public static String getOurInstance(){
        if(ourInstance == null){
           synchronized (TestSinleton.class){
                if(ourInstance == null){     
                    ourInstance="單例模式復制成功!!!";
                    System.out.print(ourInstance);
                }
            }
            //ourInstance="單例模式賦值成功!!!";
            //System.out.print(ourInstance);
        }
        return ourInstance;
    }


}

第一次判空,大部分線程被擋掉。繼續往下是一個synchronized 方法,只允許單線程執行,所以第二次判空就不會存在多個線程同時執行的情況。

多次運行程序,查看控制台:

"C:\Program Files\Java\jdk1.8.0_101\bin\java" ...
單例模式復制成功!!!
Process finished with exit code 0

發現只會打印一次了。


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved