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);
    }
}

1、實現方式一


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

package com.yefengyu.type1;

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

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

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

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

2、沒有使用懶加載,類加載就產生對象,如果始終未使用則造成內存浪費。但是該對象只有一個,浪費空間也不是很大,可以使用,編寫的時候非常簡單。

2、實現方式二

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

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;
    }
}

該方式和方式一的優缺點類似。

3、實現方式三


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

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;
    }
}

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

2、效率低下,每次調用該方法都要涉及鎖的操作。

3、不推薦使用。

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

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

4、實現方式四


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

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;
    }
}

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

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

3、推薦使用。

5、實現方式五


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

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;
    }
}

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

2、外部類裝載的時候靜態內部類不會裝載,只有使用的時候才會裝載,因此達成了懶漢式的效果。


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

一個對象即可完成所有的工作,無需大量創建對象消耗資源。比如一個長連接,建立起來就可以不斷發送數據,此時如果每來一個請求就建立一個連接,那么資源會消耗殆盡。

多線程測試:針對懶漢式

測試代碼:

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關鍵字,或者加上,查看打印效果,是打印一句還是多句。


免責聲明!

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



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