java單例holder模式,用java實現單例模式

本文目錄一覽:

如何在java中實現singleton模式

單例模式大致有五種寫法,分別為懶漢,惡漢,靜態內部類,枚舉和雙重校驗鎖。

1、懶漢寫法,常用寫法

class LazySingleton{

    private static LazySingleton singleton;

    private LazySingleton(){

    }

    public static LazySingleton getInstance(){

        if(singleton==null){

            singleton=new LazySingleton();

        }

        return singleton;

    }   

}

2、惡漢寫法,缺點是沒有達到lazy loading的效果

class HungrySingleton{

    private static HungrySingleton singleton=new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){

        return singleton;

    }

}

3、靜態內部類,優點:載入時不會初始化靜態變數INSTANCE,因為沒有主動使用,達到Lazy loading

class InternalSingleton{

    private static class SingletonHolder{

        private final static  InternalSingleton INSTANCE=new InternalSingleton();

    }   

    private InternalSingleton(){}

    public static InternalSingleton getInstance(){

        return SingletonHolder.INSTANCE;

    }

}

4、枚舉,優點:不僅能避免多線程同步問題,而且還能防止反序列化重新創建新的對象

enum EnumSingleton{

    INSTANCE;

    public void doSomeThing(){

    }

}

5、雙重校驗鎖,在當前的內存模型中無效

class LockSingleton{

    private volatile static LockSingleton singleton;

    private LockSingleton(){}

    public static LockSingleton getInstance(){

        if(singleton==null){

            synchronized(LockSingleton.class){

                if(singleton==null){

                    singleton=new LockSingleton();

                }

            }

        }

        return singleton;

    }

}

JAVA單例模式有哪些?

一、懶漢式單例

在類載入的時候不創建單例實例。只有在第一次請求實例的時候的時候創建,並且只在第一次創建後,以後不再創建該類的實例。

public

class

LazySingleton

{

/**

*

私有靜態對象,載入時候不做初始化

*/

private

static

LazySingleton

m_intance=null;

/**

*

私有構造方法,避免外部創建實例

*/

private

LazySingleton(){

}

/**

*

靜態工廠方法,返回此類的唯一實例.

*

當發現實例沒有初始化的時候,才初始化.

*/

synchronized

public

static

LazySingleton

getInstance(){

if(m_intance==null){

m_intance=new

LazySingleton();

}

return

m_intance;

}

}

二、餓漢式單例

在類被載入的時候,唯一實例已經被創建。

public

class

EagerSingleton

{

/**

*

私有的(private)唯一(static

final)實例成員,在類載入的時候就創建好了單例對象

*/

private

static

final

EagerSingleton

m_instance

=

new

EagerSingleton();

/**

*

私有構造方法,避免外部創建實例

*/

private

EagerSingleton()

{

}

/**

*

靜態工廠方法,返回此類的唯一實例.

*

@return

EagerSingleton

*/

public

static

EagerSingleton

getInstance()

{

return

m_instance;

}

}

**************************************************************************************

懶漢方式,指全局的單例實例在第一次被使用時構建;

餓漢方式,指全局的單例實例在類裝載時構建

**************************************************************************************

三、登記式單例

這個單例實際上維護的是一組單例類的實例,將這些實例存放在一個Map(登記薄)中,對於已經登記過的實例,則從工廠直接返回,對於沒有登記的,則先登記,而後返回。

public

class

RegSingleton

{

/**

*

登記薄,用來存放所有登記的實例

*/

private

static

Map

m_registry

=

new

HashMap();

//在類載入的時候添加一個實例到登記薄

static

{

RegSingleton

x

=

new

RegSingleton();

m_registry.put(x.getClass().getName(),

x);

}

/**

*

受保護的默認構造方法

*/

protected

RegSingleton()

{

}

/**

*

靜態工廠方法,返回指定登記對象的唯一實例;

*

對於已登記的直接取出返回,對於還未登記的,先登記,然後取出返回

*

@param

name

*

@return

RegSingleton

*/

public

static

RegSingleton

getInstance(String

name)

{

if

(name

==

null)

{

name

=

“RegSingleton”;

}

if

(m_registry.get(name)

==

null)

{

try

{

m_registry.put(name,

(RegSingleton)

Class.forName(name).newInstance());

}

catch

(InstantiationException

e)

{

e.printStackTrace();

}

catch

(IllegalAccessException

e)

{

e.printStackTrace();

}

catch

(ClassNotFoundException

e)

{

e.printStackTrace();

}

}

return

m_registry.get(name);

}

/**

*

一個示意性的商業方法

*

@return

String

*/

public

String

about()

{

return

“Hello,I

am

RegSingleton!”;

}

}

關於java靜態內部類形式的單例模式

static Singleton instance = new Singleton();  

static類型的成員變數,只會在新建類的對象時被執行一次。

所以static Singleton instance = new Singleton();   只有在第一次調用時,被new一次。之後獲取的都是第一次執行的對象。所以稱之為單例。

也可以使用老的寫法,比較清晰一些。

class ABC {

   private static ABC instance;

   private ABC() {}

   public ABC getInstance() {

     if (instance==null)

         instance = new ABC();

      return instance;

   }

}

這樣寫法的缺點是效率不如

class ABC {

   private static ABC instance= new ABC();

   private ABC() {}

   public ABC getInstance() {

      return instance;

   }

}

這樣寫法高。

java中的單例模式的代碼怎麼寫

我從我的博客里把我的文章粘貼過來吧,對於單例模式模式應該有比較清楚的解釋:

單例模式在我們日常的項目中十分常見,當我們在項目中需要一個這樣的一個對象,這個對象在內存中只能有一個實例,這時我們就需要用到單例。

一般說來,單例模式通常有以下幾種:

1.飢漢式單例

public class Singleton {

private Singleton(){};

private static Singleton instance = new Singleton();

public static Singleton getInstance(){

return instance;

}

}

這是最簡單的單例,這種單例最常見,也很可靠!它有個唯一的缺點就是無法完成延遲載入——即當系統還沒有用到此單例時,單例就會被載入到內存中。

在這裡我們可以做個這樣的測試:

將上述代碼修改為:

public class Singleton {

private Singleton(){

System.out.println(“createSingleton”);

};

private static Singleton instance = new Singleton();

public static Singleton getInstance(){

return instance;

}

public static void testSingleton(){

System.out.println(“CreateString”);

}

}

而我們在另外一個測試類中對它進行測試(本例所有測試都通過Junit進行測試)

public class TestSingleton {

@Test

public void test(){

Singleton.testSingleton();

}

}

輸出結果:

createSingleton

CreateString

我們可以注意到,在這個單例中,即使我們沒有使用單例類,它還是被創建出來了,這當然是我們所不願意看到的,所以也就有了以下一種單例。

2.懶漢式單例

public class Singleton1 {

private Singleton1(){

System.out.println(“createSingleton”);

}

private static Singleton1 instance = null;

public static synchronized Singleton1 getInstance(){

return instance==null?new Singleton1():instance;

}

public static void testSingleton(){

System.out.println(“CreateString”);

}

}

上面的單例獲取實例時,是需要加上同步的,如果不加上同步,在多線程的環境中,當線程1完成新建單例操作,而在完成賦值操作之前,線程2就可能判

斷instance為空,此時,線程2也將啟動新建單例的操作,那麼多個就出現了多個實例被新建,也就違反了我們使用單例模式的初衷了。

我們在這裡也通過一個測試類,對它進行測試,最後面輸出是

CreateString

可以看出,在未使用到單例類時,單例類並不會載入到內存中,只有我們需要使用到他的時候,才會進行實例化。

這種單例解決了單例的延遲載入,但是由於引入了同步的關鍵字,因此在多線程的環境下,所需的消耗的時間要遠遠大於第一種單例。我們可以通過一段測試代碼來說明這個問題。

public class TestSingleton {

@Test

public void test(){

long beginTime1 = System.currentTimeMillis();

for(int i=0;i100000;i++){

Singleton.getInstance();

}

System.out.println(“單例1花費時間:”+(System.currentTimeMillis()-beginTime1));

long beginTime2 = System.currentTimeMillis();

for(int i=0;i100000;i++){

Singleton1.getInstance();

}

System.out.println(“單例2花費時間:”+(System.currentTimeMillis()-beginTime2));

}

}

最後輸出的是:

單例1花費時間:0

單例2花費時間:10

可以看到,使用第一種單例耗時0ms,第二種單例耗時10ms,性能上存在明顯的差異。為了使用延遲載入的功能,而導致單例的性能上存在明顯差異,

是不是會得不償失呢?是否可以找到一種更好的解決的辦法呢?既可以解決延遲載入,又不至於性能損耗過多,所以,也就有了第三種單例:

3.內部類託管單例

public class Singleton2 {

private Singleton2(){}

private static class SingletonHolder{

private static Singleton2 instance=new Singleton2();

}

private static Singleton2 getInstance(){

return SingletonHolder.instance;

}

}

在這個單例中,我們通過靜態內部類來託管單例,當這個單例被載入時,不會初始化單例類,只有當getInstance方法被調用的時候,才會去載入

SingletonHolder,從而才會去初始化instance。並且,單例的載入是在內部類的載入的時候完成的,所以天生對線程友好,而且也不需要

synchnoized關鍵字,可以說是兼具了以上的兩個優點。

4.總結

一般來說,上述的單例已經基本可以保證在一個系統中只會存在一個實例了,但是,仍然可能會有其他的情況,導致系統生成多個單例,請看以下情況:

public class Singleton3 implements Serializable{

private Singleton3(){}

private static class SingletonHolder{

private static Singleton3 instance = new Singleton3();

}

public static Singleton3 getInstance(){

return SingletonHolder.instance;

}

}

通過一段代碼來測試:

@Test

public void test() throws Exception{

Singleton3 s1 = null;

Singleton3 s2 = Singleton3.getInstance();

//1.將實例串列話到文件

FileOutputStream fos = new FileOutputStream(“singleton.txt”);

ObjectOutputStream oos =new ObjectOutputStream(fos);

oos.writeObject(s2);

oos.flush();

oos.close();

//2.從文件中讀取出單例

FileInputStream fis = new FileInputStream(“singleton.txt”);

ObjectInputStream ois = new ObjectInputStream(fis);

s1 = (Singleton3) ois.readObject();

if(s1==s2){

System.out.println(“同一個實例”);

}else{

System.out.println(“不是同一個實例”);

}

}

輸出:

不是同一個實例

可以看到當我們把單例反序列化後,生成了多個不同的單例類,此時,我們必須在原來的代碼中加入readResolve()函數,來阻止它生成新的單例

public class Singleton3 implements Serializable{

private Singleton3(){}

private static class SingletonHolder{

private static Singleton3 instance = new Singleton3();

}

public static Singleton3 getInstance(){

return SingletonHolder.instance;

}

//阻止生成新的實例

public Object readResolve(){

return SingletonHolder.instance;

}

}

再次測試時,就可以發現他們生成的是同一個實例了。

在java開發中,為什麼要使用單例模式?

java單例模式確保一個類只有一個實例,自行提供這個實例並向整個系統提供這個實例。

特點:

一個類只能有一個實例;

自己創建這個實例;

整個系統都要使用這個實例。

Singleton模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。在很多操作中,比如建立目錄 資料庫連接都需要這樣的單線程操作。一些資源管理器常常設計成單例模式。

外部資源:譬如每台計算機可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印作業同時輸出到印表機中。每台計算機可以有若干個通信埠,系統應當集中管理這些通信埠,以避免一個通信埠被兩個請求同時調用。

內部資源,譬如,大多數的軟體都有一個(甚至多個)屬性文件存放系統配置。這樣的系統應當由一個對象來管理這些屬性文件。

單例模式,能避免實例重複創建;

單例模式,應用於避免存在多個實例引起程序邏輯錯誤的場合;

單例模式,較節約內存。

什麼是Java單例模式啊?

樓主您好

java模式之單例模式:

單例模式確保一個類只有一個實例,自行提供這個實例並向整個系統提供這個實例。

特點:

1,一個類只能有一個實例

2,自己創建這個實例

3,整個系統都要使用這個實例

例: 在下面的對象圖中,有一個”單例對象”,而”客戶甲”、”客戶乙” 和”客戶丙”是單例對象的三個客戶對象。可以看到,所有的客戶對象共享一個單例對象。而且從單例對象到自身的連接線可以看出,單例對象持有對自己的引用。

Singleton模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。在很多操作中,比如建立目錄 資料庫連接都需要這樣的單線程操作。一些資源管理器常常設計成單例模式。

外部資源:譬如每台計算機可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印作業同時輸出到印表機中。每台計算機可以有若干個通信埠,系統應當集中管理這些通信埠,以避免一個通信埠被兩個請求同時調用。內部資源,譬如,大多數的軟體都有一個(甚至多個)屬性文件存放系統配置。這樣的系統應當由一個對象來管理這些屬性文件。

一個例子:Windows 回收站。

在整個視窗系統中,回收站只能有一個實例,整個系統都使用這個惟一的實例,而且回收站自行提供自己的實例。因此,回收站是單例模式的應用。

兩種形式:

1,餓漢式單例類

public class Singleton {

private Singleton(){}

//在自己內部定義自己一個實例,是不是很奇怪?

//注意這是private 只供內部調用

private static Singleton instance = new Singleton();

//這裡提供了一個供外部訪問本class的靜態方法,可以直接訪問

public static Singleton getInstance() {

return instance;

}

}

2,懶漢式單例類

public class Singleton {

private static Singleton instance = null;

public static synchronized Singleton getInstance() {

//這個方法比上面有所改進,不用每次都進行生成對象,只是第一次

//使用時生成實例,提高了效率!

if (instance==null)

instance=new Singleton();

return instance; }

}

第二中形式是lazy initialization,也就是說第一次調用時初始Singleton,以後就不用再生成了。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/257129.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-15 12:43
下一篇 2024-12-15 12:44

相關推薦

  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29
  • Java 8 Group By 會影響排序嗎?

    是的,Java 8中的Group By會對排序產生影響。本文將從多個方面探討Group By對排序的影響。 一、Group By的概述 Group By是SQL中的一種常見操作,它…

    編程 2025-04-29

發表回復

登錄後才能評論