更新時(shí)間:2022-03-23 11:42:35 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2161次
在本文中,我們將了解如何創(chuàng)建單例類。閱讀本文后,您將能夠根據(jù)您的使用、簡單性和消除瓶頸來創(chuàng)建您的單例類。
在 Java 中有很多方法可以做到這一點(diǎn)。所有這些方式在模式的實(shí)現(xiàn)上都有所不同,但最終,它們都實(shí)現(xiàn)了單個(gè)實(shí)例的相同最終結(jié)果。
這是創(chuàng)建單例類的最簡單方法。在這種情況下,類的對象是在JVM加載到內(nèi)存時(shí)創(chuàng)建的。這是通過直接為引用分配一個(gè)實(shí)例來完成的。
當(dāng)程序總是使用這個(gè)類的實(shí)例,或者創(chuàng)建實(shí)例的資源和時(shí)間成本不是太大時(shí),可以使用它。
// Java code to create singleton class by
// Eager Initialization
public class GFG
{
// public instance initialized when loading the class
private static final GFG instance = new GFG();
private GFG()
{
// private constructor
}
public static GFG getInstance(){
return instance;
}
}
優(yōu)點(diǎn):
實(shí)現(xiàn)起來非常簡單。
可能導(dǎo)致資源浪費(fèi)。因?yàn)轭惖膶?shí)例總是被創(chuàng)建,無論它是否需要。
如果不需要,CPU 時(shí)間也會(huì)浪費(fèi)在創(chuàng)建實(shí)例上。
異常處理是不可能的。
這也是 Eager 初始化的子部分。唯一的區(qū)別是對象是在靜態(tài)塊中創(chuàng)建的,因此我們可以訪問它的創(chuàng)建,例如異常處理。以這種方式,對象也是在類加載時(shí)創(chuàng)建的。
當(dāng)使用急切初始化創(chuàng)建對象時(shí)有可能出現(xiàn)異常時(shí),可以使用它。
// Java code to create singleton class
// Using Static block
public class GFG
{
// public instance
public static GFG instance;
private GFG()
{
// private constructor
}
static
{
// static block to initialize instance
instance = new GFG();
}
}
優(yōu)點(diǎn):
實(shí)現(xiàn)起來非常簡單。
無需實(shí)現(xiàn) getInstance() 方法。可以直接訪問實(shí)例。
異常可以在靜態(tài)塊中處理。
可能導(dǎo)致資源浪費(fèi)。因?yàn)轭惖膶?shí)例總是被創(chuàng)建,無論它是否需要。
如果不需要,CPU 時(shí)間也會(huì)浪費(fèi)在創(chuàng)建實(shí)例上。
在此方法中,僅在需要時(shí)才創(chuàng)建對象。這可以防止資源浪費(fèi)。需要返回實(shí)例的 getInstance() 方法的實(shí)現(xiàn)。有一個(gè)空檢查,如果沒有創(chuàng)建對象然后創(chuàng)建,否則返回以前創(chuàng)建的。為了確保該類不能以任何其他方式實(shí)例化,構(gòu)造函數(shù)是最終的。由于對象是在方法中創(chuàng)建的,因此它確保除非需要,否則不會(huì)創(chuàng)建對象。實(shí)例是私有的,因此沒有人可以直接訪問它。
它可以在單線程環(huán)境中使用,因?yàn)槎鄠€(gè)線程可以破壞單例屬性,因?yàn)樗鼈兛梢酝瑫r(shí)訪問 get 實(shí)例方法并創(chuàng)建多個(gè)對象。
//Java Code to create singleton class
// With Lazy initialization
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
//method to return instance of class
public static GFG getInstance()
{
if (instance == null)
{
// if instance is null, initialize
instance = new GFG();
}
return instance;
}
}
優(yōu)點(diǎn):
只有在需要時(shí)才創(chuàng)建對象。它可以克服資源消耗和 CPU 時(shí)間的浪費(fèi)。
在方法中也可以進(jìn)行異常處理。
每次都必須檢查 null 的條件。
無法直接訪問實(shí)例。
在多線程環(huán)境中,它可能會(huì)破壞單例屬性。
創(chuàng)建了一個(gè)線程安全的單例,這樣即使在多線程環(huán)境中也可以保持單例屬性。為了使單例類線程安全,getInstance() 方法是同步的,因此多個(gè)線程不能同時(shí)訪問它。
// Java program to create Thread Safe
// Singleton class
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
//synchronized method to control simultaneous access
synchronized public static GFG getInstance()
{
if (instance == null)
{
// if instance is null, initialize
instance = new GFG();
}
return instance;
}
}
優(yōu)點(diǎn):
延遲初始化是可能的。
它也是線程安全的。
getInstance() 方法是同步的,因此會(huì)導(dǎo)致性能下降,因?yàn)槎鄠€(gè)線程無法同時(shí)訪問它。
在這種機(jī)制中,我們克服了同步代碼的開銷問題。在此方法中,getInstance 不同步,但創(chuàng)建實(shí)例的塊是同步的,因此必須等待最少數(shù)量的線程,這只是第一次。
// Java code to explain double check locking
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
public static GFG getInstance()
{
if (instance == null)
{
//synchronized block to remove overhead
synchronized (GFG.class)
{
if(instance==null)
{
// if instance is null, initialize
instance = new GFG();
}
}
}
return instance;
}
}
優(yōu)點(diǎn):
延遲初始化是可能的。
它也是線程安全的。
由于 synchronized 關(guān)鍵字,性能開銷得到了降低。
第一次,它會(huì)影響性能。
在Java5之前,內(nèi)存模型有很多問題,以上方法在多線程環(huán)境中的某些場景下會(huì)導(dǎo)致失敗。所以,Bill Pugh 提出了一個(gè)內(nèi)部靜態(tài)類的概念,用于單例。
// Java code for Bill Pugh Singleton Implementation
public class GFG
{
private GFG()
{
// private constructor
}
// Inner class to provide instance of class
private static class BillPughSingleton
{
private static final GFG INSTANCE = new GFG();
}
public static GFG getInstance()
{
return BillPughSingleton.INSTANCE;
}
}
加載單例類時(shí),不會(huì)加載內(nèi)部類,因此在加載類時(shí)不會(huì)創(chuàng)建對象。只有在調(diào)用 getInstance() 方法時(shí)才會(huì)創(chuàng)建內(nèi)部類。所以它可能看起來像急切的初始化,但它是延遲初始化。
這是最廣泛Java單例設(shè)計(jì)模式使用的方法,因?yàn)樗皇褂猛健?/p>
相關(guān)閱讀

初級 202925

初級 203221

初級 202629

初級 203743