欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Singleton詳解

系統(tǒng) 1965 0

單態(tài)定義:
Singleton模式主要作用是保證在Java應(yīng)用程序中,一個(gè)類Class只有一個(gè)實(shí)例存在。

Singleton模式就為我們提供了這樣實(shí)現(xiàn)的可能。使用Singleton的好處還在于可以節(jié)省內(nèi)存,因?yàn)樗拗屏?
實(shí)例的個(gè)數(shù),有利于Java垃圾回收(garbage collection)。

使用Singleton注意事項(xiàng):
有時(shí)在某些情況下,使用Singleton并不能達(dá)到Singleton的目的,如有多個(gè)Singleton對象同時(shí)被不同的類
裝入器裝載;在EJB這樣的分布式系統(tǒng)中使用也要注意這種情況,因?yàn)镋JB是跨服務(wù)器,跨JVM的

單態(tài)模式的演化:
單態(tài)模式是個(gè)簡單的模式,但是這個(gè)簡單的模式也有很多復(fù)雜的東西。

(注意:在這里補(bǔ)充一下,現(xiàn)在單態(tài)模式其實(shí)有一個(gè)寫法是不錯的見這里: http://www.blogjava.net/dreamstone/archive/2007/02/27/101000.html ,但還是建議看完這篇文章,因?yàn)榻忉尩氖虑槭遣灰粯拥模@里說的是為什么double-checked不能使用.)
一,首先最簡單的單態(tài)模式,單態(tài)模式1
import java.util.*;
class Singleton
{
private static Singleton instance;
private Vector v;
private boolean inUse;

private Singleton()
{
??? v = new Vector();
??? v.addElement(new Object());
??? inUse = true;
}

public static Singleton getInstance()
{
??? if (instance == null)????????? //1
????? instance = new Singleton(); //2
??? return instance;?????????????? //3
}
}
這個(gè)單態(tài)模式是不安全的,為什么說呢 ?因?yàn)闆]考慮多線程,如下情況
Thread 1 調(diào)用getInstance() 方法,并且判斷instance是null,然後進(jìn)入if模塊,
在實(shí)例化instance之前,
Thread 2搶占了Thread 1的cpu
Thread 2 調(diào)用getInstance() 方法,并且判斷instance是null,然後進(jìn)入if模塊,
Thread 2 實(shí)例化instance 完成,返回
Thread 1 再次實(shí)例化instance
這個(gè)單態(tài)已經(jīng)不在是單態(tài)

二,為了解決剛才的問題:單態(tài)模式2
public static synchronized Singleton getInstance()
{
if (instance == null)????????? //1
??? instance = new Singleton(); //2
return instance;?????????????? //3
}
采用同步來解決,這種方式解決了問題,但是仔細(xì)分析
正常的情況下只有第一次時(shí)候,進(jìn)入對象的實(shí)例化,須要同步,
其它時(shí)候都是直接返回已經(jīng)實(shí)例化好的instance不須要同步,
大家都知到在一個(gè)多線程的程序中,如果同步的消耗是很大的,很容易造成瓶頸

三,為了解決上邊的問題:單態(tài)模式3,加入同步
public static Singleton getInstance()
{
if (instance == null)
{
??? synchronized(Singleton.class) {
????? instance = new Singleton();
??? }
}
return instance;
}
同步改成塊同步,而不使用函數(shù)同步,但是仔細(xì)分析,
又回到了模式一的狀態(tài),再多線程的時(shí)候根本沒有解決問題

四,為了對應(yīng)上邊的問題:單態(tài)模式4,也就是很多人采用的Double-checked locking
public static Singleton getInstance()
{
if (instance == null)
{
??? synchronized(Singleton.class) { //1
????? if (instance == null)????????? //2
??????? instance = new Singleton(); //3
??? }
}
return instance;
}
這樣,模式一中提到的問題解決了。不會出現(xiàn)多次實(shí)例化的現(xiàn)象
當(dāng)?shù)谝淮芜M(jìn)入的時(shí)候,保正實(shí)例化時(shí)候的單態(tài),在實(shí)例化后,多線程訪問的時(shí)候直接返回,不須要進(jìn)入同步模塊,
既實(shí)現(xiàn)了單態(tài),又沒有損失性能。表面上看我們的問題解決了,但是再仔細(xì)分析:
我們來假象這中情況:
Thread 1 :進(jìn)入到//3位置,執(zhí)行new Singleton(),但是在構(gòu)造函數(shù)剛剛開始的時(shí)候被Thread2搶占cpu
Thread 2 :進(jìn)入getInstance(),判斷instance不等于null,返回instance,
(instance已經(jīng)被new,已經(jīng)分配了內(nèi)存空間,但是沒有初始化數(shù)據(jù))
Thread 2 :利用返回的instance做某些操做,失敗或者異常
Thread 1 :取得cpu初始化完成
過程中可能有多個(gè)線程取到了沒有完成的實(shí)例,并用這個(gè)實(shí)例作出某些操做。
-----------------------------------------
出現(xiàn)以上的問題是因?yàn)?
mem = allocate();???????????? //分配內(nèi)存
instance = mem;?????????????? //標(biāo)記instance非空
????????????????????????????? //未執(zhí)行構(gòu)造函數(shù),thread 2從這里進(jìn)入
ctorSingleton(instance);????? //執(zhí)行構(gòu)造函數(shù)
????????????????????????????? //返回instance
------------------------------------------?????????????????????????????

五,證明上邊的假想是可能發(fā)生的,字節(jié)碼是用來分析問題的最好的工具,可以利用它來分析
下邊一段程序:(為了分析方便,所以漸少了內(nèi)容)
字節(jié)碼的使用方法見這里, 利用字節(jié)碼分析問題
class Singleton
{
private static Singleton instance;
private boolean inUse;
private int val;

private Singleton()
{
??? inUse = true;
??? val = 5;
}
public static Singleton getInstance()
{
??? if (instance == null)
????? instance = new Singleton();
??? return instance;
}
}
得到的字節(jié)碼???????????????????????????
;asm code generated for getInstance
054D20B0?? mov???????? eax,[049388C8]????? ;load instance ref
054D20B5?? test??????? eax,eax???????????? ;test for null
054D20B7?? jne???????? 054D20D7
054D20B9?? mov???????? eax,14C0988h
054D20BE?? call??????? 503EF8F0??????????? ;allocate memory
054D20C3?? mov???????? [049388C8],eax????? ;store pointer in
?????????????????????????????????????????? ;instance ref. instance
?????????????????????????????????????????? ;non-null and ctor
?????????????????????????????????????????? ;has not run
054D20C8?? mov???????? ecx,dword ptr [eax]
054D20CA?? mov???????? dword ptr [ecx],1?? ;inline ctor - inUse=true;
054D20D0?? mov???????? dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7?? mov???????? ebx,dword ptr ds:[49388C8h]
054D20DD?? jmp???????? 054D20B0

上邊的字節(jié)碼證明,猜想是有可能實(shí)現(xiàn)的

六:好了,上邊證明Double-checked locking可能出現(xiàn)取出錯誤數(shù)據(jù)的情況,那么我們還是可以解決的
public static Singleton getInstance()
{
if (instance == null)
{
??? synchronized(Singleton.class) {????? //1
????? Singleton inst = instance;???????? //2
????? if (inst == null)
????? {
??????? synchronized(Singleton.class) { //3
????????? inst = new Singleton();??????? //4
??????? }
??????? instance = inst;???????????????? //5
????? }
??? }
}
return instance;
}
利用Double-checked locking 兩次同步,中間變量,解決上邊的問題。
(下邊這段話我只能簡單的理解,翻譯過來不好,所以保留原文,list 7是上邊的代碼,list 8是下邊的
The code in Listing 7 doesn't work because of the current definition of the memory model.
The Java Language Specification (JLS) demands that code within a synchronized block
not be moved out of a synchronized block. However, it does not say that
code not in a synchronized block cannot be moved into a synchronized block.
A JIT compiler would see an optimization opportunity here.
This optimization would remove the code at
//4 and the code at //5, combine it and generate the code shown in Listing 8:)
-------------------------------------------------
list 8
public static Singleton getInstance()
{
if (instance == null)
{
??? synchronized(Singleton.class) {????? //1
????? Singleton inst = instance;???????? //2
????? if (inst == null)
????? {
??????? synchronized(Singleton.class) { //3
????????? //inst = new Singleton();????? //4
????????? instance = new Singleton();??????????????
??????? }
??????? //instance = inst;?????????????? //5
????? }
??? }
}
return instance;
}
If this optimization takes place, you have the same out-of-order write problem we discussed earlier.
如果這個(gè)優(yōu)化發(fā)生,將再次發(fā)生上邊提到的問題,取得沒有實(shí)例化完成的數(shù)據(jù)。
-------------------------------------------------

以下部分為了避免我翻譯錯誤誤導(dǎo)打家,保留原文

Another idea is to use the keyword volatile for the variables inst and instance.
According to the JLS (see Resources), variables declared volatile are supposed to
be sequentially consistent, and therefore, not reordered.
But two problems occur with trying to use volatile to fix the problem with
double-checked locking:

The problem here is not with sequential consistency.
Code is being moved, not reordered.

Many JVMs do not implement volatile correctly regarding sequential consistency anyway.
The second point is worth expanding upon. Consider the code in Listing 9:

Listing 9. Sequential consistency with volatile

class test
{
private volatile boolean stop = false;
private volatile int num = 0;

public void foo()
{
??? num = 100;??? //This can happen second
??? stop = true; //This can happen first
??? //...
}

public void bar()
{
??? if (stop)
????? num += num; //num can == 0!
}
//...
}

According to the JLS, because stop and num are declared volatile,
they should be sequentially consistent. This means that if stop is ever true,
num must have been set to 100.
However, because many JVMs do not implement the sequential consistency feature of volatile,
you cannot count on this behavior.
Therefore, if thread 1 called foo and thread 2 called bar concurrently,
thread 1 might set stop to true before num is set to 100.
This could lead thread 2 to see stop as true, but num still set to 0.
There are additional problems with volatile and the atomicity of 64-bit variables,
but this is beyond the scope of this article.
See Resources for more information on this topic.

簡單的理解上邊這段話,使用volatile有可能能解決問題,volatile被定義用來保正一致性,但是很多虛擬機(jī)
并沒有很好的實(shí)現(xiàn)volatile,所以使用它也會存在問題。

最終的解決方案:
(1),單態(tài)模式2,使用同步方法
(2),放棄同步,使用一個(gè)靜態(tài)變量,如下
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();

private Singleton()
{
??? v = new Vector();
??? inUse = true;
??? //...
}

public static Singleton getInstance()
{
??? return instance;
}
}
但使用靜態(tài)變量也會存在問題,問題見 這篇文章

而且如在文章開頭提到的,使用EJB跨服務(wù)器,跨JVM的情況下,單態(tài)更是問題

好了是不是感覺單態(tài)模式根本沒法使用了,其實(shí)上邊都是特殊情況,這中特殊情況的出現(xiàn)是有條件的,只要
根據(jù)你的具體應(yīng)用,回避一些,就能解決問題,所以單態(tài)還是可以使用的。但是在使用前慎重,自己考慮好自己
的情況適合哪種情況。

?

即使是double-check也解決不了問題,但是有人解決了這個(gè)問題。
佩服啊。實(shí)在是巧妙,如此簡單
注意:在多個(gè)虛擬機(jī)的情況下這個(gè)方法還是不能用的,但是一般情況下是可以的。
實(shí)現(xiàn)方式:

public class Singleton {???
??
??
static class SingletonHolder {???
????
static Singleton instance = new Singleton();???
?? }
???
??
??
public static Singleton getInstance() {???
????
return SingletonHolder.instance;???
?? }
???
??
}
??

這個(gè)寫法的發(fā)明者是Google公司的Bob lee。
他還寫了個(gè)輕量級IoC容器,據(jù)說不要配制文件,性能比spring快100倍。感覺100倍有些夸張,不過可以看看。

Singleton詳解


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!?。?/p>

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲国产精品久久 | 红桃一区 | 中文成人在线 | 日韩欧美一区二区三区在线视频 | 日本三级免费 | 亚洲一区在线观看视频 | 日本高清视频www夜色资源网 | 久久国产精品视频 | 亚洲精品国产a久久久久久 亚洲国产精品第一页 | 久久大综合 | 久草在线播放 | 国产精品久久久久久久午夜 | 午夜资源 | 欧美jlzz18性欧美 | 五月婷婷在线播放 | 清纯唯美综合 | 久久综合一个色综合网 | 国产手机精品一区二区 | 免费中文字幕视频 | 天天干天天操天天碰 | 人人干免费 | 国产精品资源网站在线观看 | 日本香港三级和澳门三级 | 欧美8一10sex性hd | 久草福利在线视频 | 精品视频在线播放 | 日本久久综合视频 | 一区二区三区国产好 | 亚洲品质自拍视频 | 日本高清免费不卡在线播放 | 久久精品国产一区二区三区不卡 | 香蕉久久一区二区不卡无毒影院 | 色精品一区二区三区 | 91福利免费观看 | 欧美日韩国产在线人成dvd | 91视频 - 88av| 91精品啪在线观看国产91九色 | 婷婷免费视频 | 日韩精品 电影一区 亚洲 | wankzhd | 免费午夜视频在线观看 |