設計模式(三)——JDK中的那些單例
在 中介紹了單例的概念、用途、實現方式、如何防止被序列化破壞等。單例模式在JDK原始碼中也有多處應用。本文通過JDK(java 8)中幾個典型的單例的使用來複習一下單例模式,並且通過這種實際應用來深入理解一下單例的用法與實現方式。
java.lang.Runtime
Runtime
類封裝了Java執行時的環境。每一個java程式實際上都是啟動了一個JVM程式,那麼每個JVM程式都是對應這一個Runtime例項,此例項是由JVM為其例項化的。每個 Java 應用程式都有一個 Runtime 類例項,使應用程式能夠與其執行的環境相連線。
由於Java是單程式的,所以,在一個JVM中,Runtime的例項應該只有一個。所以應該使用單例來實現。
public
class
Runtime
{
private
static Runtime currentRuntime
=
new
Runtime
(
)
;
public
static Runtime
getRuntime
(
)
{
return currentRuntime
;
}
private
Runtime
(
)
{
}
}
以上程式碼為JDK中
Runtime
類的部分實現,可以看到,這其實是餓漢式單例模式。在該類第一次被classloader載入的時候,這個例項就被建立出來了。
一般不能例項化一個
Runtime
物件,應用程式也不能建立自己的 Runtime 類例項,但可以通過getRuntime
方法獲取當前Runtime
執行時物件的引用。
GUI中的單例
除了
Runtime
是典型的單例以外。JDK中還有幾個類是單例的,他們都是GUI中的類。這幾個單例的類和
Runtime
最大的區別就在於他們並不是餓漢模式,也就是他們都是惰性初始化的懶漢單例。如果分析其原因的話也比較簡單:那就是他們並不需要事先建立好,只要在第一次真正用到的時候再建立就可以了。因為很多時候我們並不是用Java的GUI和其中的物件。如果使用餓漢單例的話會影響JVM的啟動速度。
由於Java的強項並不是做GUI,所以這幾個類其實並不會經常被用到。筆者也沒用過。把程式碼貼到這裡,從單例的實現的角度簡單分析一下。
java.awt.Toolkit#getDefaultToolkit()
public abstract
class
Toolkit
{
/**
* The default toolkit.
*/
private
static Toolkit toolkit
;
public
static synchronized Toolkit
getDefaultToolkit
(
)
{
if
(toolkit
==
null
)
{
java
.security
.AccessController
.
doPrivileged
(
new
java
.security
.PrivilegedAction
<Void
>
(
)
{
public Void
run
(
)
{
Class
<
?
> cls
=
null
;
String nm
= System
.
getProperty
(
"awt.toolkit"
)
;
try
{
cls
= Class
.
forName
(nm
)
;
}
catch
(ClassNotFoundException e
)
{
ClassLoader cl
= ClassLoader
.
getSystemClassLoader
(
)
;
if
(cl
!=
null
)
{
try
{
cls
= cl
.
loadClass
(nm
)
;
}
catch
(final ClassNotFoundException ignored
)
{
throw
new
AWTError
(
"Toolkit not found: "
+ nm
)
;
}
}
}
try
{
if
(cls
!=
null
)
{
toolkit
=
(Toolkit
)cls
.
newInstance
(
)
;
if
(GraphicsEnvironment
.
isHeadless
(
)
)
{
toolkit
=
new
HeadlessToolkit
(toolkit
)
;
}
}
}
catch
(final InstantiationException ignored
)
{
throw
new
AWTError
(
"Could not instantiate Toolkit: "
+ nm
)
;
}
catch
(final IllegalAccessException ignored
)
{
throw
new
AWTError
(
"Could not access Toolkit: "
+ nm
)
;
}
return
null
;
}
}
)
;
loadAssistiveTechnologies
(
)
;
}
return toolkit
;
}
}
上面的程式碼是
Toolkit
類的單例實現。這裡類載入時只靜態宣告瞭私有
toolkit
並沒有建立
Toolkit
例項物件,延遲載入加快了JVM啟動速度。
單例模式作為一種建立模式,這裡在依賴載入的時候應用了另一種建立物件的方式,不是
new
新的物件,因為Toolkit
本身是個抽象類不能例項化物件,而是通過反射機制載入類並建立新的例項。
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
public abstract
class
GraphicsEnvironment
{
private
static GraphicsEnvironment localEnv
;
public
static synchronized GraphicsEnvironment
getLocalGraphicsEnvironment
(
)
{
if
(localEnv
==
null
)
{
localEnv
=
createGE
(
)
;
}
return localEnv
;
}
}
這裡類載入時只靜態宣告瞭私有
localEnv
並沒有建立例項物件。在
GraphicsEnvironment
類被第一次呼叫時會建立該物件。這裡沒有貼出的
createGE()
方法也是通過
的方式建立物件的。
java.awt.Desktop#getDesktop()
public
class
Desktop
{
public
static synchronized Desktop
getDesktop
(
)
{
if
(GraphicsEnvironment
.
isHeadless
(
)
)
throw
new
HeadlessException
(
)
;
if
(
!Desktop
.
isDesktopSupported
(
)
)
{
throw
new
UnsupportedOperationException
(
"Desktop API is not "
+
"supported on the current platform"
)
;
}
//java學習交流:737251827 進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
sun
.awt
.AppContext context
= sun
.awt
.AppContext
.
getAppContext
(
)
;
Desktop desktop
=
(Desktop
)context
.
get
(Desktop
.class
)
;
if
(desktop
==
null
)
{
desktop
=
new
Desktop
(
)
;
context
.
put
(Desktop
.class
, desktop
)
;
}
return desktop
;
}
}
上面的程式碼看上去和單例不太一樣。但是實際上也是執行緒安全的懶漢式單例。獲取物件的時候先去環境容器中查詢是否存在,不存在例項則建立一個例項。
以上三個類的獲取例項的方法都通過同步方法的方式保證了執行緒安全。
Runtime類是通過靜態初始化的方式保證其執行緒安全的。
總結
文中介紹了四個單例的例子,其中有一個是餓漢式單例,三個是懶漢式單例。通過JDK中的實際應用我們可以得出以下結論:
當一個類的物件只需要或者只可能有一個時,應該考慮單例模式。
如果一個類的例項應該在JVM初始化時被建立出來,應該考慮使用餓漢式單例。
如果一個類的例項不需要預先被建立,也許這個類的例項並不一定能用得上,也許這個類的例項建立過程比較耗費時間,也許就是真的沒必須提前建立。那麼應該考慮懶漢式單例。
在使用懶漢式單例的時候,應該考慮到執行緒的安全性問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010294/viewspace-2847255/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Javascript設計模式(三)單例模式JavaScript設計模式單例
- 設計模式快速學習(三)單例模式設計模式單例
- 設計模式(三)----建立型模式之單例模式(一)設計模式單例
- 設計模式 單例模式設計模式單例
- 設計模式——單例模式設計模式單例
- [設計模式] 單例模式設計模式單例
- 設計模式-單例模式設計模式單例
- 設計模式 —— 單例模式設計模式單例
- 設計模式(單例模式)設計模式單例
- 設計模式之單例設計模式設計模式單例
- 單例設計模式單例設計模式
- 【設計模式】三、單例模式(10分鐘深度搞定)設計模式單例
- Java設計模式-單例模式Java設計模式單例
- 設計模式之單例模式設計模式單例
- Java設計模式【單例模式】Java設計模式單例
- 常用設計模式-單例模式設計模式單例
- 設計模式之---單例模式設計模式單例
- 設計模式(二)——單例模式設計模式單例
- Java設計模式 | 單例模式Java設計模式單例
- 001設計模式:單例模式設計模式單例
- # Python設計模式 單例模式Python設計模式單例
- 設計模式一(單例模式)設計模式單例
- 設計模式之☞單例模式設計模式單例
- Java設計模式——單例模式Java設計模式單例
- Java設計模式--單例模式Java設計模式單例
- Python設計模式——單例模式Python設計模式單例
- 設計模式—singleton(單例模式)設計模式單例
- python設計模式-單例模式Python設計模式單例
- Java設計模式–單例模式Java設計模式單例
- js設計模式--單例模式JS設計模式單例
- 設計模式(一)_單例模式設計模式單例
- 設計模式-單例模式、多例模式設計模式單例
- 設計模式總結 —— 單例設計模式設計模式單例
- JavaScript設計模式初探--單例設計模式JavaScript設計模式單例
- 設計模式之單例設計模式單例
- Singleton 單例設計模式單例設計模式
- java單例設計模式Java單例設計模式
- Java常用設計模式-單例模式Java設計模式單例