java單例設計模式

單例設計模式是在軟件系統中採用必定的方法,保證某個類只能存在一個實例對象,而且該類只能有一個靜態方法來獲取該對象。java

注意下面各種實現方式中的測試代碼都同樣:須要注意導入的包路徑便可。設計模式

package com.yefengyu;

import com.yefengyu.type2.Singleton;


public class Client
{
    public static void main(String[] args)
    {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
    }
}

一、實現方式一


該方式是靜態常量實現的餓漢式類加載的時候便建立了實例):安全

package com.yefengyu.type1;

public class Singleton
{
    //類內部實例化
    private final static Singleton INSTANCE = new Singleton();

    //構造器私有化,防止new對象
    private Singleton()
    {
    }

    //對外提供公有方法調用
    public static Singleton getInstance()
    {
        return INSTANCE;
    }
}

一、類加載的時候實例化,防止多線程問題。多線程

二、沒有使用懶加載,類加載就產生對象,若是始終未使用則形成內存浪費。可是該對象只有一個,浪費空間也不是很大,可使用,編寫的時候很是簡單。測試

二、實現方式二

該方式是靜態代碼塊實現的餓漢式spa

package com.yefengyu.type2;

public class Singleton
{
    private final static Singleton INSTANCE;

    static
    {
        //使用靜態代碼塊生成對象
        INSTANCE = new Singleton();
    }

    //構造器私有化,防止new對象
    private Singleton()
    {
    }

    //對外提供公有方法調用
    public static Singleton getInstance()
    {
        return INSTANCE;
    }
}

該方式和方式一的優缺點相似。線程

三、實現方式三


該方式是同步方法實現懶漢式只有第一次使用的時候才建立實例設計

package com.yefengyu.type3;

public class Singleton
{
    private static Singleton instance;

    //構造器私有化,防止new對象
    private Singleton()
    {
    }

    //只有在第一次使用的時候構造實例對象,使用synchronized避免多線程問題
    public static synchronized Singleton getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

一、解決了線程不安全問題code

二、效率低下,每次調用該方法都要涉及鎖的操做。對象

三、不推薦使用。

問:java設計模式的單例模式,在懶漢式中一開始聲明的類的實例化對象爲何只用private static聲明,但沒有加final關鍵字?而在餓漢式中聲明實例是使用了private static final修飾?

答:若是是final非static成員,必須在構造器、代碼塊、或者直接定義賦值;若是是final static成員變量,必須直接賦值或者在靜態代碼塊中賦值。而在懶漢式中若是直接賦值就達不到延遲加載的效果。

四、實現方式四


該方式是同步代碼塊實現懶漢式。

package com.yefengyu.type4;

public class Singleton
{
    private static Singleton instance;

    //構造器私有化,防止new對象
    private Singleton()
    {
    }

    //只有在第一次使用的時候構造實例對象,使用synchronized代碼塊和雙重判斷避免多線程問題,而且提供效率
    public static Singleton getInstance()
    {
        if (instance == null)
        {
            synchronized (Singleton.class)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

一、解決了線程不安全問題

二、效率高,只有前面的少數線程可能會獲取鎖,只要實例被建立,後面的線程通常只需第一個if判斷就返回了對象。

三、推薦使用。

五、實現方式五


該方式是靜態內部類實現懶漢式。

package com.yefengyu.type5;

public class Singleton
{
    private static Singleton instance;

    //構造器私有化,防止new對象
    private Singleton()
    {
    }

    //靜態內部類,在外部類加載的時候不會加載靜態內部類
    private static class SingletonInstance
    {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance()
    {
        //只有在使用到靜態內部類的時候纔會加載,而且經過類加載機制保證在初始化的時候只有一個實例產生
        return SingletonInstance.INSTANCE;
    }
}

一、線程安全,使用類加載機制保證初始化時只有一個線程。

二、外部類裝載的時候靜態內部類不會裝載,只有使用的時候纔會裝載,所以達成了懶漢式的效果。


單例設計模式的使用場景?

一個對象便可完成全部的工做,無需大量建立對象消耗資源。好比一個長鏈接,創建起來就能夠不斷髮送數據,此時若是每來一個請求就創建一個鏈接,那麼資源會消耗殆盡。

多線程測試:針對懶漢式

測試代碼:

for (int i = 0; i < 1000; i++)
{
    new Thread(() -> {
        Singleton.getInstance();
    }).start();
}

在new實例的時候加上打印,如:

public static synchronized Singleton getInstance()
{
    if (instance == null)
    {
        System.out.println("建立實例");
        instance = new Singleton();
    }
    return instance;
}
這個時候能夠去掉synchronized關鍵字,或者加上,查看打印效果,是打印一句仍是多句。
相關文章
相關標籤/搜索