基於Java利用static實現單例模式

一、之前舊的寫法

class Singleton{
    private Singleton() {}
    private static Singleton instance = null;
    public synchronized static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
}

就利用Sington.getInstace就可以瞭,獲得的是同一個實例。

上面那個代碼有兩個優點:

  • 懶加載,把在堆創建實例這個行為延遲到類的使用時。
  • 鎖效果,防止生成多個實例,因為synchronized修飾這個static方法,所以相當於給這個方法加上瞭一個類鎖🔒。

二、static代碼塊的效果

先來看一段代碼:

 

class StaticClass{
    private static int a = 1;
    static{
        System.out.println("語句1");
        System.out.println("語句2");
    }
    static{
        System.out.println("語句3");
        System.out.println("語句4");
    }
}

當在多個線程同時觸發類的初始化過程的時候(在初始化過程,類的static變量會被賦值為JVM默認值並且static代碼塊會被執行),為什麼static不會被多次執行?因為有可能兩個線程同時檢測到類還沒被初始化,然後都執行static代碼塊,結果就把語句1234多打印瞭,為什麼上述情況不會發生。

Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Class.forName("StaticClass");//這一行觸發類的初始化導致靜態代碼塊執行
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Class.forName("StaticClass");//同樣
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });
        thread2.start();

結果如下:

語句1
語句2
語句3
語句4

有一段英文對其進行瞭解釋:

static initialization block can be triggered from multiple parallel threads (when the loading of the class happens in the first time), Java runtime guarantees that it will be executed only once and in thread-safe manner + when we have more than 1 static block – it guarantees the sequential execution of the blocks, 也就是說,java runtime幫我們做瞭兩件事:

  • 在並行線程中,都出現瞭第一次初始化類的情況,保證類的初始化隻執行一次。
  • 保證static代碼塊的順序執行

三、單例的另一種寫法

有瞭對static的知識的瞭解之後,我們可以寫出這樣的單例模式:

class Singleton{
    private Singleton() {}
    private static class NestedClass{
       static Singleton instance = new Singleton();//這條賦值語句會在初始化時才運行
    }
    public static Singleton getInstance() {
        return NestedClass.instance;
    }
}
  • 懶加載,因為static語句會在初始化時才賦值運行,達到瞭懶加載的效果。
  • 鎖🔒的效果由Java runtime保證,虛擬機幫我們保證static語句在初始化時隻會執行一次。

四、總結

如果不知道static的基礎知識和虛擬機類加載的知識,我可能並不會知道這一種方法。理論永遠先行於技術,要學好理論才能從根本上提升自己。

到此這篇關於基於Java利用static實現單例模式的文章就介紹到這瞭,更多相關static實現單例模式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: