★yesjoy★
★
總在爬山 所以艱辛;總在尋夢(mèng) 所以苦痛
★
BlogJava
首頁(yè)
新隨筆
聯(lián)系
聚合
管理
隨筆 - 71 文章 - 15 trackbacks - 0
<
2025年5月
>
日
一
二
三
四
五
六
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
★
因?yàn)榭诳?,上帝?chuàng)造了水;
★
因?yàn)楹诎担系蹌?chuàng)造了火;
★
因?yàn)槲倚枰笥?,所以上帝讓你?lái)到我身邊
╱◥█◣
|田|田|
╬╬╬╬╬╬╬╬╬╬╬
If only I have such a house!
〖總在爬山 所以艱辛〗
Email:myesjoy@yahoo.com.cn
NickName:yesjoy
MSN:myesjoy@hotmail.com
QQ:150230516
〖總在尋夢(mèng) 所以苦痛〗
常用鏈接
我的隨筆
我的評(píng)論
我的參與
最新評(píng)論
留言簿
(3)
給我留言
查看公開(kāi)留言
查看私人留言
隨筆分類
Hibernate學(xué)習(xí)總結(jié)(1)
J2EE架構(gòu)
Struts學(xué)習(xí)總結(jié)(1)
隨筆檔案
2018年8月 (1)
2007年6月 (3)
2007年5月 (8)
2007年4月 (21)
2007年3月 (6)
2007年1月 (1)
2006年12月 (3)
2006年8月 (1)
2006年4月 (1)
2006年3月 (1)
文章分類
AOP(面向方面編程)(5)
C/C++語(yǔ)言算法總結(jié)(16)
CORBA 學(xué)習(xí)(1)
DB2學(xué)習(xí)(1)
Hibernate學(xué)習(xí)(8)
J2EE結(jié)構(gòu)(3)
java.applet包(2)
java.awt包(4)
java.util包 (2)
JAVA代碼查錯(cuò)(2)
Java基礎(chǔ)知識(shí)(3)
Java常用類
JAVA編程規(guī)范(2)
Oracle學(xué)習(xí)(3)
PowerDesigner設(shè)計(jì)(4)
Spring學(xué)習(xí)(3)
Structs學(xué)習(xí)(15)
公眾資源(1)
存儲(chǔ)設(shè)備(1)
工作流基本知識(shí)(6)
常用Jar包介紹和應(yīng)用(1)
數(shù)據(jù)庫(kù)備份/恢復(fù)方案(2)
數(shù)據(jù)庫(kù)的查詢及性能優(yōu)化(1)
數(shù)據(jù)庫(kù)設(shè)計(jì)(4)
數(shù)據(jù)結(jié)構(gòu)(1)
算法總結(jié)(7)
設(shè)計(jì)模式(4)
讀書世界(2)
軟件工程學(xué)(13)
需求管理(1)
項(xiàng)目經(jīng)驗(yàn)總結(jié)(2)
文章檔案
2014年1月 (1)
2007年8月 (10)
2007年7月 (7)
2007年6月 (19)
2007年5月 (9)
2007年4月 (3)
2007年3月 (5)
2007年1月 (3)
2006年11月 (7)
2006年10月 (6)
2006年8月 (5)
2006年7月 (1)
2006年4月 (5)
2006年3月 (7)
2006年2月 (20)
2006年1月 (14)
Hibernate在線
HIBERNATE - 符合Java習(xí)慣的關(guān)系數(shù)據(jù)庫(kù)持久化
Java友情
§BlogJava - 鐵手劍譜§
§oksonic博客§
§sampa : colin’s blog§
§人生代碼§
Java認(rèn)證
IT認(rèn)證傳奇站
JAVA SCJD認(rèn)證 SCJP認(rèn)證 JAVA程序設(shè)計(jì)員認(rèn)證網(wǎng)站
linux經(jīng)典
‖LinuxABC.NET‖
Linux菜鳥(niǎo)到高手,就在LinuxABC.NET
OA系統(tǒng)
¤易能協(xié)同辦公系統(tǒng)¤
流程管理、知識(shí)管理、客戶關(guān)系管理、輔助辦公
¤黃城網(wǎng)絡(luò)辦公系統(tǒng)3.0¤
B/S結(jié)構(gòu),適用于Intranet/Internet應(yīng)用,實(shí)現(xiàn)無(wú)地域限制的全球辦公,具有郵件管理、業(yè)務(wù)管理、網(wǎng)絡(luò)硬盤、智能工作流等功能。
Spring在線
【Spring Framework 開(kāi)發(fā)參考手冊(cè)】
Structs在線
【IBM_Struts 應(yīng)用專題】
【Structs官方網(wǎng)站】
專家專欄
§張孝祥專欄_Java基礎(chǔ)§
§芮祥麟的專欄_SOA§
企業(yè)信息化
¢ERPHome¢
¢e-works中國(guó)制造業(yè)信息化門戶¢
管理_技術(shù)_信息化
大型設(shè)備共享系統(tǒng)
武漢大學(xué)儀器設(shè)備共享平臺(tái)
湖南高校大型儀器設(shè)備共用網(wǎng)
工作流
∫中國(guó)工作流論壇∫
∫工作流管理聯(lián)盟WfMC ∫
∫工作流網(wǎng)∫
業(yè)務(wù)過(guò)程建模與工作流管理技術(shù)論壇
工作流產(chǎn)品
℃協(xié)同軟件開(kāi)發(fā)者社區(qū) :: 首頁(yè)℃
網(wǎng)上購(gòu)書
China-Pub網(wǎng)上書店
卓越網(wǎng): 網(wǎng)上購(gòu)物
當(dāng)當(dāng)網(wǎng),全球最大的中文網(wǎng)上商城
淘寶網(wǎng)
搜索
最新評(píng)論
1.?re: DetachedCriteria關(guān)聯(lián)查詢
dddd
--sss
2.?re: Struts提供的強(qiáng)大的HTML標(biāo)簽庫(kù)總結(jié)[未登錄](méi)
是
--哈哈
3.?re: 打印出1900~2000年中所有的閏年
不錯(cuò)
--網(wǎng)通
4.?re: DetachedCriteria關(guān)聯(lián)查詢
@name
是有重復(fù)數(shù)據(jù),該怎么解決啊
--996416660
5.?re: DetachedCriteria關(guān)聯(lián)查詢
這個(gè)查詢的話,會(huì)多出重復(fù)數(shù)據(jù)。
--name
閱讀排行榜
1.?在struts中如何使用showModalDialog() (1035)
2.?eclipse中進(jìn)行hibernate映射的步驟(854)
3.?2006年12月份工作總結(jié)之一(601)
4.?這五天來(lái)的工作。。。(411)
5.?籃球的意義(394)
評(píng)論排行榜
1.?十多年后再發(fā)個(gè)隨筆,感覺(jué)很奇怪(0)
2.?買了移動(dòng)硬盤(0)
3.?這五天來(lái)的工作。。。(0)
4.?高效工作,高效生活,我的人生!(0)
5.?安全意識(shí)在哪里?(0)
單例模式完全剖析(2)---- 探究簡(jiǎn)單卻又使人迷惑的單例模式
測(cè)試單例模式
接下來(lái),我使用與log4j相對(duì)應(yīng)的JUnit來(lái)測(cè)試單例類,它會(huì)貫穿在這篇文章余下的部分。如果你對(duì)JUnit或log4j不很熟悉,請(qǐng)參考相關(guān)資源。
例2是一個(gè)用JUnit測(cè)試?yán)?的單例模式的案例:
例2.一個(gè)單例模式的案例
import
org.apache.log4j.
Logger
;
import
junit.framework.
Assert
;
import
junit.framework.
TestCase
;
public
class
SingletonTest
extends
TestCase
{
private
ClassicSingleton sone =
null
, stwo =
null
;
private
static
Logger
logger =
Logger
.getRootLogger();
public
SingletonTest(
String
name) {
super
(name);
}
public
void
setUp() {
logger.info(
"getting singleton..."
);
sone = ClassicSingleton.getInstance();
logger.info(
"...got singleton: "
+ sone);
logger.info(
"getting singleton..."
);
stwo = ClassicSingleton.getInstance();
logger.info(
"...got singleton: "
+ stwo);
}
public
void
testUnique() {
logger.info(
"checking singletons for equality"
);
Assert
.assertEquals(
true
, sone == stwo);
}
}
例2兩次調(diào)用ClassicSingleton.getInstance(),并且把返回的引用存儲(chǔ)在成員變量中。方法testUnique()會(huì)檢查這些引用看它們是否相同。例3是這個(gè)測(cè)試案例的輸出:
例3.是這個(gè)測(cè)試案例的輸出
Buildfile: build.xml
init:
[echo] Build 20030414 (14-04-2003 03:08)
compile:
run-test-text:
[java] .INFO main: [b]getting singleton...[/b]
[java] INFO main: [b]created singleton:[/b] Singleton@e86f41
[java] INFO main: ...got singleton: Singleton@e86f41
[java] INFO main: [b]getting singleton...[/b]
[java] INFO main: ...got singleton: Singleton@e86f41
[java] INFO main: checking singletons
for
equality
[java]
Time
: 0.032
[java] OK (1 test)
正如前面的清單所示,例2的簡(jiǎn)單測(cè)試順利通過(guò)----通過(guò)ClassicSingleton.getInstance()獲得的兩個(gè)單例類的引用確實(shí)相同;然而,你要知道這些引用是在單線程中得到的。下面的部分著重于用多線程測(cè)試單例類。
多線程因素的考慮
在例1中的ClassicSingleton.getInstance()方法由于下面的代碼而不是線程安全的:
1:
if
(instance ==
null
) {
2: instance =
new
Singleton();
3: }
如果一個(gè)線程在第二行的賦值語(yǔ)句發(fā)生之前切換,那么成員變量instance仍然是null,然后另一個(gè)線程可能接下來(lái)進(jìn)入到if塊中。在這種情況下,兩個(gè)不同的單例類實(shí)例就被創(chuàng)建。不幸的是這種假定很少發(fā)生,這樣這種假定也很難在測(cè)試期間出現(xiàn)(譯注:在這可能是作者對(duì)很少出現(xiàn)這種情況而導(dǎo)致無(wú)法測(cè)試從而使人們放松警惕而感到嘆惜)。為了演示這個(gè)線程輪換,我得重新實(shí)現(xiàn)例1中的那個(gè)類。例4就是修訂后的單例類:
例4.人為安排的方式
import
org.apache.log4j.
Logger
;
public
class
Singleton {
private
static
Singleton singleton =
null
;
private
static
Logger
logger =
Logger
.getRootLogger();
private
static
boolean
firstThread =
true
;
protected
Singleton() {
// Exists only to defeat instantiation.
}
public
static
Singleton getInstance() {
if
(singleton ==
null
) {
simulateRandomActivity();
singleton =
new
Singleton();
}
logger.info(
"created singleton: "
+ singleton);
return
singleton;
}
private
static
void
simulateRandomActivity() {
try
{
if
(firstThread) {
firstThread =
false
;
logger.info(
"sleeping..."
);
// This nap should give the second thread enough time
// to get by the first thread.
Thread
.currentThread().sleep(50);
}
}
catch
(
InterruptedException
ex) {
logger.warn(
"Sleep interrupted"
);
}
}
}
除了在這個(gè)清單中的單例類強(qiáng)制使用了一個(gè)多線程錯(cuò)誤處理,例4類似于例1中的單例類。在getInstance()方法第一次被調(diào)用時(shí),調(diào)用這個(gè)方法的線程會(huì)休眠50毫秒以便另外的線程也有時(shí)間調(diào)用getInstance()并創(chuàng)建一個(gè)新的單例類實(shí)例。當(dāng)休眠的線程覺(jué)醒時(shí),它也會(huì)創(chuàng)建一個(gè)新的單例類實(shí)例,這樣我們就有兩個(gè)單例類實(shí)例。盡管例4是人為如此的,但它卻模擬了第一個(gè)線程調(diào)用了getInstance()并在沒(méi)有完成時(shí)被切換的真實(shí)情形。
例5測(cè)試了例4的單例類:
例5.失敗的測(cè)試
import
org.apache.log4j.
Logger
;
import
junit.framework.
Assert
;
import
junit.framework.
TestCase
;
public
class
SingletonTest
extends
TestCase
{
private
static
Logger
logger =
Logger
.getRootLogger();
private
static
Singleton singleton =
null
;
public
SingletonTest(
String
name) {
super
(name);
}
public
void
setUp() {
singleton =
null
;
}
public
void
testUnique()
throws
InterruptedException
{
// Both threads call Singleton.getInstance().
Thread
threadOne =
new
Thread
(
new
SingletonTestRunnable()),
threadTwo =
new
Thread
(
new
SingletonTestRunnable());
threadOne.start();
threadTwo.start();
threadOne.join();
threadTwo.join();
}
private
static
class
SingletonTestRunnable
implements
Runnable
{
public
void
run() {
// Get a reference to the singleton.
Singleton s = Singleton.getInstance();
// Protect singleton member variable from
// multithreaded access.
synchronized
(SingletonTest.
class
) {
if
(singleton ==
null
)
// If local reference is null...
singleton = s;
// ...set it to the singleton
}
// Local reference must be equal to the one and
// only instance of Singleton; otherwise, we have two
// Singleton instances.
Assert
.assertEquals(
true
, s == singleton);
}
}
}
例5的測(cè)試案例創(chuàng)建兩個(gè)線程,然后各自啟動(dòng),等待完成。這個(gè)案例保持了一個(gè)對(duì)單例類的靜態(tài)引用,每個(gè)線程都會(huì)調(diào)用Singleton.getInstance()。如果這個(gè)靜態(tài)成員變量沒(méi)有被設(shè)置,那么第一個(gè)線程就會(huì)將它設(shè)為通過(guò)調(diào)用getInstance()而得到的引用,然后這個(gè)靜態(tài)變量會(huì)與一個(gè)局部變量比較是否相等。
在這個(gè)測(cè)試案例運(yùn)行時(shí)會(huì)發(fā)生一系列的事情:第一個(gè)線程調(diào)用getInstance(),進(jìn)入if塊,然后休眠;接著,第二個(gè)線程也調(diào)用getInstance()并且創(chuàng)建了一個(gè)單例類的實(shí)例。第二個(gè)線程會(huì)設(shè)置這個(gè)靜態(tài)成員變量為它所創(chuàng)建的引用。第二個(gè)線程檢查這個(gè)靜態(tài)成員變量與一個(gè)局部備份的相等性。然后測(cè)試通過(guò)。當(dāng)?shù)谝粋€(gè)線程覺(jué)醒時(shí),它也會(huì)創(chuàng)建一個(gè)單例類的實(shí)例,并且它不會(huì)設(shè)置那個(gè)靜態(tài)成員變量(因?yàn)榈诙€(gè)線程已經(jīng)設(shè)置過(guò)了),所以那個(gè)靜態(tài)變量與那個(gè)局部變量脫離同步,相等性測(cè)試即告失敗。例6列出了例5的輸出:
例6.例5的輸出
Buildfile: build.xml
init:
[echo] Build 20030414 (14-04-2003 03:06)
compile:
run-test-text:
INFO
Thread
-1: sleeping...
INFO
Thread
-2: created singleton: Singleton@7e5cbd
INFO
Thread
-1: created singleton: Singleton@704ebb
junit.framework.
AssertionFailedError
: expected: but was:
at junit.framework.
Assert
.fail(Assert.java:47)
at junit.framework.
Assert
.failNotEquals(Assert.java:282)
at junit.framework.
Assert
.assertEquals(Assert.java:64)
at junit.framework.
Assert
.assertEquals(Assert.java:149)
at junit.framework.
Assert
.assertEquals(Assert.java:155)
at SingletonTest$SingletonTestRunnable.run(Unknown
Source
)
at java.lang.
Thread
.run(
Thread
.java:554)
[java] .
[java]
Time
: 0.577
[java] OK (1 test)
到現(xiàn)在為止我們已經(jīng)知道例4不是線程安全的,那就讓我們看看如何修正它。
同步
要使例4的單例類為線程安全的很容易----只要像下面一個(gè)同步化getInstance()方法:
public
synchronized
static
Singleton getInstance() {
if
(singleton ==
null
) {
simulateRandomActivity();
singleton =
new
Singleton();
}
logger.info(
"created singleton: "
+ singleton);
return
singleton;
}
在同步化getInstance()方法后,我們就可以得到例5的測(cè)試案例返回的下面的結(jié)果:
Buildfile: build.xml
init:
[echo] Build 20030414 (14-04-2003 03:15)
compile:
[javac] Compiling 2 source files
run-test-text:
INFO
Thread
-1: sleeping...
INFO
Thread
-1: created singleton: Singleton@ef577d
INFO
Thread
-2: created singleton: Singleton@ef577d
[java] .
[java]
Time
: 0.513
[java] OK (1 test)
這此,這個(gè)測(cè)試案例工作正常,并且多線程的煩惱也被解決;然而,機(jī)敏的讀者可能會(huì)認(rèn)識(shí)到getInstance()方法只需要在第一次被調(diào)用時(shí)同步。因?yàn)橥降男阅荛_(kāi)銷很昂貴(同步方法比非同步方法能降低到100次左右),或許我們可以引入一種性能改進(jìn)方法,它只同步單例類的getInstance()方法中的賦值語(yǔ)句。
一種性能改進(jìn)的方法
尋找一種性能改進(jìn)方法時(shí),你可能會(huì)選擇像下面這樣重寫getInstance()方法:
public
static
Singleton getInstance() {
if
(singleton ==
null
) {
synchronized
(Singleton.
class
) {
singleton =
new
Singleton();
}
}
return
singleton;
}
這個(gè)代碼片段只同步了關(guān)鍵的代碼,而不是同步整個(gè)方法。然而這段代碼卻不是線程安全的??紤]一下下面的假定:線程1進(jìn)入同步塊,并且在它給singleton成員變量賦值之前線程1被切換。接著另一個(gè)線程進(jìn)入if塊。第二個(gè)線程將等待直到第一個(gè)線程完成,并且仍然會(huì)得到兩個(gè)不同的單例類實(shí)例。有修復(fù)這個(gè)問(wèn)題的方法嗎?請(qǐng)讀下去。
雙重加鎖檢查
初看上去,雙重加鎖檢查似乎是一種使懶漢式實(shí)例化為線程安全的技術(shù)。下面的代碼片段展示了這種技術(shù):
public
static
Singleton getInstance() {
if
(singleton ==
null
) {
synchronized
(Singleton.
class
) {
if
(singleton ==
null
) {
singleton =
new
Singleton();
}
}
}
return
singleton;
}
如果兩個(gè)線程同時(shí)訪問(wèn)getInstance()方法會(huì)發(fā)生什么?想像一下線程1進(jìn)行同步塊馬上又被切換。接著,第二個(gè)線程進(jìn)入if 塊。當(dāng)線程1退出同步塊時(shí),線程2會(huì)重新檢查看是否singleton實(shí)例仍然為null。因?yàn)榫€程1設(shè)置了singleton成員變量,所以線程2的第二次檢查會(huì)失敗,第二個(gè)單例類實(shí)例也就不會(huì)被創(chuàng)建。似乎就是如此。
不幸的是,雙重加鎖檢查不會(huì)保證正常工作,因?yàn)榫幾g器會(huì)在Singleton的構(gòu)造方法被調(diào)用之前隨意給singleton賦一個(gè)值。如果在singleton引用被賦值之后而被初始化之前線程1被切換,線程2就會(huì)被返回一個(gè)對(duì)未初始化的單例類實(shí)例的引用。
一個(gè)改進(jìn)的線程安全的單例模式實(shí)現(xiàn)
例7列出了一個(gè)簡(jiǎn)單、快速而又是線程安全的單例模式實(shí)現(xiàn):
例7.一個(gè)簡(jiǎn)單的單例類
public
class
Singleton {
public
final
static
Singleton INSTANCE =
new
Singleton();
private
Singleton() {
// Exists only to defeat instantiation.
}
}
這段代碼是線程安全的是因?yàn)殪o態(tài)成員變量一定會(huì)在類被第一次訪問(wèn)時(shí)被創(chuàng)建。你得到了一個(gè)自動(dòng)使用了懶漢式實(shí)例化的線程安全的實(shí)現(xiàn);你應(yīng)該這樣使用它:
Singleton singleton = Singleton.INSTANCE;
singleton.dothis();
singleton.dothat();
...
當(dāng)然萬(wàn)事并不完美,前面的Singleton只是一個(gè)折衷的方案;如果你使用那個(gè)實(shí)現(xiàn),你就無(wú)法改變它以便后來(lái)你可能想要允許多個(gè)單例類的實(shí)例。用一種更折哀的單例模式實(shí)現(xiàn)(通過(guò)一個(gè)getInstance()方法獲得實(shí)例)你可以改變這個(gè)方法以便返回一個(gè)唯一的實(shí)例或者是數(shù)百個(gè)實(shí)例中的一個(gè).你不能用一個(gè)公開(kāi)且是靜態(tài)的(public static)成員變量這樣做.
你可以安全的使用例7的單例模式實(shí)現(xiàn)或者是例1的帶一個(gè)同步的getInstance()方法的實(shí)現(xiàn).然而,我們必須要研究另一個(gè)問(wèn)題:你必須在編譯期指定這個(gè)單例類,這樣就不是很靈活.一個(gè)單例類的注冊(cè)表會(huì)讓我們?cè)谶\(yùn)行期指定一個(gè)單例類.
posted on 2006-02-14 15:33
★yesjoy★
閱讀(225)
評(píng)論(0)
編輯
收藏
所屬分類:
設(shè)計(jì)模式
新用戶注冊(cè)
刷新評(píng)論列表
只有注冊(cè)用戶
登錄
后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問(wèn)
管理
相關(guān)文章:
單例模式完全剖析(2)---- 探究簡(jiǎn)單卻又使人迷惑的單例模式
單例模式完全剖析(1)---- 探究簡(jiǎn)單卻又使人迷惑的單例模式
java23種模式一點(diǎn)就通
設(shè)計(jì)模式的基礎(chǔ)
Copyright ©2025 ★yesjoy★ Powered by:
博客園
模板提供:
滬江博客
主站蜘蛛池模板:
heyzo亚洲精品日韩
|
**aaaaa毛片免费
|
特级毛片在线大全免费播放
|
亚洲国产精品美女久久久久
|
亚洲六月丁香婷婷综合
|
亚洲一卡2卡4卡5卡6卡在线99
|
亚洲精品在线免费观看
|
亚洲精品美女久久久久9999
|
亚洲的天堂av无码
|
久久亚洲AV无码精品色午夜
|
亚洲精品视频在线观看视频
|
亚洲一欧洲中文字幕在线
|
亚洲jjzzjjzz在线播放
|
亚洲欧洲精品成人久久曰
|
亚洲.国产.欧美一区二区三区
|
爱爱帝国亚洲一区二区三区
|
免费国产在线精品一区
|
jzzjzz免费观看大片免费
|
中文字幕无线码免费人妻
|
一个人免费日韩不卡视频
|
亚洲免费网站在线观看
|
最近免费中文字幕大全视频
|
亚洲欧洲日韩国产一区二区三区
|
亚洲国产成人久久精品app
|
亚洲一区二区三区写真
|
亚洲AV中文无码乱人伦下载
|
亚洲国产一区在线
|
亚洲精品中文字幕无乱码麻豆
|
亚洲Av永久无码精品一区二区
|
免费人妻精品一区二区三区
|
你好老叔电影观看免费
|
中国人xxxxx69免费视频
|
天天干在线免费视频
|
国产精品亚洲w码日韩中文
|
久久精品国产亚洲av麻豆
|
亚洲一级片在线观看
|
国产亚洲精品91
|
波多野结衣免费一区视频
|
免费观看在线禁片
|
免费可以看黄的视频s色
|
国产一区二区三区免费看
|