導航:首頁 > 編程語言 > Java類的單例模式

Java類的單例模式

發布時間:2023-01-20 15:40:07

java模式設計之單例模式(一)

作為對象的創建模式[GOF ] 單例模式確保某一個類只有一個實例 而且自行實例化並向整個系統提供這個實例 這個類稱為單例類

單例模式的要點

單例單例

顯然單例模式的要點有三個 一是某各類只能有一個實例 二是它必須自行創建這個事例 三是它必須自行向整個系統提供這個實例 在下面的對象圖中 有一個 單例對象 而 客戶甲 客戶乙 和 客戶丙 是單例對象的三個客戶對象 可以看到 所有的客戶對象共享一個單例對象 而且從單例對象到自身的連接線可以看出 單例對象持有對自己的引用

資源管理

一些資源管理器常常設計成單例模式

在計算機系統中 需要管理的資源包括軟體外部資源 譬如每台計算機可以有若干個列印機 但只能有一個Printer Spooler 以避免兩個列印作業同時輸出到列印機中 每台計算機可以有若干傳真卡 但是只應該有一個軟體負責管理傳真卡 以避免出現兩份傳真作業同時傳到傳真卡中的情況 每台計算機可以有若干通信埠 系統應當集中管理這些通信埠 以避免一個通信埠同時被兩個請求同時調用

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

需要管理的軟體內部資源也包括譬如負責記錄網站來訪人數的部件 記錄軟體系統內部事件 出錯信息的部件 或是對系統的表現進行檢查的部件等 這些部件都必須集中管理 不可政出多頭

這些資源管理器構件必須只有一個實例 這是其一 它們必須自行初始化 這是其二 允許整個系統訪問自己這是其三 因此 它們都滿足單例模式的條件 是單例模式的應用

一個例子 Windows 回收站

Windows x 以後的視窗系統中都有一個回收站 下圖就顯示了Windows 的回收站

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

雙重檢查成例

在本章最後的附錄里研究了雙重檢查成例 雙重檢查成例與單例模式並無直接的關系 但是由於很多C 語言設計師在單例模式裡面使用雙重檢查成例 所以這一做法也被很多Java 設計師所模仿 因此 本書在附錄里提醒讀者 雙重檢查成例在Java 語言里並不能成立 詳情請見本章的附錄

單例模式的結構

單例模式有以下的特點

…… 單例類只可有一個實例

…… 單例類必須自己創建自己這惟一的實例

…… 單例類必須給所有其他對象提供這一實例

雖然單例模式中的單例類被限定只能有一個實例 但是單例模式和單例類可以很容易被推廣到任意且有限多個實例的情況 這時候稱它為多例模式(Multiton Pattern) 和多例類(Multiton Class) 請見 專題 多例(Multiton )模式與多語言支持 一章 單例類的簡略類圖如下所示

由於Java 語言的特點 使得單例模式在Java 語言的實現上有自己的特點 這些特點主要表現在單例類如何將自己實例化上

餓漢式單例類餓漢式單例類是在Java 語言里實現得最為簡便的單例類 下面所示的類圖描述了一個餓漢式單例類的典型實現

從圖中可以看出 此類已經自已將自己實例化

代碼清單 餓漢式單例類

public class EagerSingleton { private static final EagerSingleton m_instance = new EagerSingleton() /** * 私有的默認構造子*/ private EagerSingleton() { } /** * 靜態工廠方法*/ public static EagerSingleton getInstance()

{

Java 與模式return m_instance }

讀者可以看出 在這個類被載入時 靜態變數m_instance 會被初始化 此時類的私有構造子會被調用 這時候 單例類的惟一實例就被創建出來了

Java 語言中單例類的一個最重要的特點是類的構造子是私有的 從而避免外界利用構造子直接創建出任意多的實例 值得指出的是 由於構造子是私有的 因此 此類不能被繼承

懶漢式單例類

與餓漢式單例類相同之處是 類的構造子是私有的 與餓漢式單例類不同的是 懶漢式單例類在第一次被引用時將自己實例化 如果載入器是靜態的 那麼在懶漢式單例類被載入時不會將自己實例化 如下圖所示 類圖中給出了一個典型的餓漢式單例類實現

代碼清單 懶漢式單例類

package javapatterns singleton demos public class LazySingleton { private static LazySingleton m_instance = null /** * 私有的默認構造子 保證外界無法直接實例化*/ private LazySingleton() { } /** * 靜態工廠方法 返還此類的惟一實例*/ synchronized public static LazySingleton getInstance()

{ if (m_instance == null)

{ m_instance = new LazySingleton() } return m_instance }

讀者可能會注意到 在上面給出懶漢式單例類實現里對靜態工廠方法使用了同步化 以處理多線程環境 有些設計師在這里建議使用所謂的 雙重檢查成例 必須指出的是 雙重檢查成例 不可以在Java 語言中使用 不十分熟悉的讀者 可以看看後面給出的小節

同樣 由於構造子是私有的 因此 此類不能被繼承 餓漢式單例類在自己被載入時就將自己實例化 即便載入器是靜態的 在餓漢式單例類被載入時仍會將自己實例化 單從資源利用效率角度來講 這個比懶漢式單例類稍差些

從速度和反應時間角度來講 則比懶漢式單例類稍好些 然而 懶漢式單例類在實例化時 必須處理好在多個線程同時首次引用此類時的訪問限制問題 特別是當單例類作為資源控制器 在實例化時必然涉及資源初始化 而資源初始化很有可能耗費時間 這意味著出現多線程同時首次引用此類的機率變得較大

餓漢式單例類可以在Java 語言內實現 但不易在C++ 內實現 因為靜態初始化在C++ 里沒有固定的順序 因而靜態的m_instance 變數的初始化與類的載入順序沒有保證 可能會出問題 這就是為什麼GoF 在提出單例類的概念時 舉的例子是懶漢式的 他們的書影響之大 以致Java 語言中單例類的例子也大多是懶漢式的 實際上 本書認為餓漢式單例類更符合Java 語言本身的特點

登記式單例類

登記式單例類是GoF 為了克服餓漢式單例類及懶漢式單例類均不可繼承的缺點而設計的 本書把他們的例子翻譯為Java 語言 並將它自己實例化的方式從懶漢式改為餓漢式 只是它的子類實例化的方式只能是懶漢式的 這是無法改變的 如下圖所示是登記式單例類的一個例子 圖中的關系線表明 此類已將自己實例化

代碼清單 登記式單例類

import java util HashMap public class RegSingleton { static private HashMap m_registry = new HashMap() static { RegSingleton x = new RegSingleton() m_registry put( x getClass() getName() x) } /** * 保護的默認構造子*/ protected RegSingleton() {} /** * 靜態工廠方法 返還此類惟一的實例*/ static public RegSingleton getInstance(String name)

{ if (name == null)

{ name = javapatterns singleton demos RegSingleton } if (m_registry get(name) == null)

{ try { m_registry put( name Class forName(name) newInstance() ) } catch(Exception e)

{ System out println( Error happened ) } return (RegSingleton) (m_registry get(name) ) } /** * 一個示意性的商業方法*/ public String about()

{ return Hello I am RegSingleton }它的子類RegSingletonChild 需要父類的幫助才能實例化 下圖所示是登記式單例類子類的一個例子 圖中的關系表明 此類是由父類將子類實例化的

下面是子類的源代碼

代碼清單 登記式單例類的子類

import java util HashMap public class RegSingletonChild extends RegSingleton { public RegSingletonChild() {} /** * 靜態工廠方法*/ static public RegSingletonChild getInstance()

{ return (RegSingletonChild)

RegSingleton getInstance( javapatterns singleton demos RegSingletonChild ) } /** * 一個示意性的商業方法*/ public String about()

{ return Hello I am RegSingletonChild }

在GoF 原始的例子中 並沒有getInstance() 方法 這樣得到子類必須調用的getInstance(String name)方法並傳入子類的名字 因此很不方便 本章在登記式單例類子類的例子里 加入了getInstance() 方法 這樣做的好處是RegSingletonChild 可以通過這個方法 返還自已的實例 而這樣做的缺點是 由於數據類型不同 無法在RegSingleton 提供這樣一個方法 由於子類必須允許父類以構造子調用產生實例 因此 它的構造子必須是公開的 這樣一來 就等於允許了以這樣方式產生實例而不在父類的登記中 這是登記式單例類的一個缺點

lishixin/Article/program/Java/gj/201311/27416

Ⅱ Java程序性能優化-單例模式(1)

單例模式( )

單例模式是設計模式中使用最為普遍的模式之一 它是一種對象創建模式 用於產生一個對象的具體實例 它可以確保系統中一個類只產生一個實例 在Java語言中 這樣的行為能帶來兩大好處

( )對於頻繁使用的對象 可以省略創建對象所花費的時間 這對於那些重量級對象而言 是非常可觀的一筆系統開銷

( )由於new操作的次數減少 因而對系統內存的使用頻率也會降低 這將減輕GC壓力 縮短GC停頓時間

因此對於系統的關鍵組件和被頻繁使用的對象 使用單例模式便可以有效地改善系統的性能

單例模式的參與者非常簡單 只有單例類和使用者兩個 如表 所示

表 單例模式角色

它的基本結構如圖 所示

圖 單例模式類圖

單例模式的核心在於通過一個介面返回唯一的對象實例 一個簡單的單例實現如下

public class Singleton {

private Singleton(){

System out println( Singleton is create ) //創建單例的過程可能會比較慢

}

private static Singleton instance = new Singleton()

public static Singleton getInstance() {

return instance;

}

}

注意代碼中的重點標注部分 首先單例類必須要有一個private訪問級別的構造函數 只有這樣 才能確保單例不會在系統中的其他代碼內被實例化 這點是相當重要的 其次 instance成員變數和getInstance()方法必須是static的

注意 單例模式是非常常用的一種結構 幾乎所有的系統中都可以找到它的身影 因此 希望讀者可以通過本節 了解單例模式的幾種實現方式及其各自的特點

這種單例的實現方式非常簡單 而且十分可靠 它唯一的不足僅是無法對instance實例做延遲載入 假如單例的創建過程很慢 而由於instance成員變數是static定義的 因此在JVM載入單例類時 單例對象就會被建立 如果此時 這個單例類在系統中還扮演其他角色 那麼在任何使用這個單例類的地方都會初始化這個單例變數 而不管是否會被用到 比如單例類作為String工廠 用於創建一些字元串(該類既用於創建單例Singleton 又用於創建String對象)

public class Singleton {

private Singleton() {

System out println( Singleton is create )

//創建單例的過程可能會比較慢

}

private static Singleton instance = new Singleton()

public static Singleton getInstance() {

return instance;

}

public static void createString(){ //這是模擬單例類扮演其他角色

System out println( createString in Singleton )

}

}

返回目錄 Java程序性能優化 讓你的Java程序更快 更穩定

編輯推薦

Java程序設計培訓視頻教程

J EE高級框架實戰培訓視頻教程

J ME移動開發實戰教學視頻

Visual C++音頻/視頻技術開發與實戰

Oracle索引技術

lishixin/Article/program/Java/gj/201311/27837

Ⅲ 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中實現單例模式

單例模式1:
public
class
singleton{
private
static
singleton
st
=
null;
private
singleton(){
}
public
static
singleton
getinstance(){
if(st
==
null){
st
=
new
singleton();
}
return
st;
}
}
單例模式2:
public
class
singleton{
private
static
singleton
st
=
new
singleton();
private
singleton(){
}
public
static
singleton
getinstance(){
return
st;
}
}
多線程1:
導入thread所在的包
public
class
mythread1
extends
thread{
public
void
run(){
xxxxx寫自己的代碼
}
}
多線程2
導入runnable所在的包
public
class
mythread2
implements
runnable{
public
void
run(){
xxxxx寫自己的代碼
}
}
另寫一個測試類,在main方法中這樣寫:
thread
t
=
new
mythread1();
或者
runnable
r
=
new
mythread2();
thread
t
=
new
thread(r);

Ⅳ 什麼是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,以後就不用再生成了。

閱讀全文

與Java類的單例模式相關的資料

熱點內容
騰訊伺服器如何上傳源碼 瀏覽:739
單片機的原理概述 瀏覽:508
火控pdf 瀏覽:267
如何復制雲伺服器centos環境 瀏覽:984
債權pdf 瀏覽:299
紅色番字的app怎麼下載 瀏覽:876
雲伺服器流程教課 瀏覽:702
中國農業銀行app怎麼沒有網 瀏覽:997
幾率表演算法 瀏覽:902
程序員理工科 瀏覽:708
企業郵箱登錄收件伺服器地址 瀏覽:558
計算機思維與演算法設計的重要性 瀏覽:664
linux刷新磁碟命令 瀏覽:76
我的世界如何查看伺服器種子pc 瀏覽:284
linuxlamp編譯安裝 瀏覽:609
枚舉演算法ppt 瀏覽:184
cmd查看進程命令 瀏覽:956
手機內怎麼刪除APP 瀏覽:834
魚群和鳥群演算法區別 瀏覽:93
pdf尺寸設置 瀏覽:211