網(wǎng)上處處都是懶漢,餓漢形式。給兩個Demo就算過去了吧。
餓漢單例形式:在類加載的時分,就開端實例化了。
publicclassHungrySingleton{privatestaticHungrySingletonone=newHungrySingleton();privateHungrySingleton(){}publicstaticHungrySingletongetInstance(){returnone;
}publicstaticvoidmain(String[]args){
HungrySingletonone1=HungrySingleton.getInstance();
HungrySingletonone2=HungrySingleton.getInstance();
System.out.println(one1==one2);
}
}
懶漢形式:在第一次獲取實例化對象的時分,開端實例化。
publicclassLazySingleton{privatestaticLazySingletonone=null;privateLazySingleton(){
}publicstaticLazySingletongetInstance(){if(one==null){
one=newLazySingleton();
}returnone;
}publicstaticvoidmain(String[]args){
LazySingletonone1=LazySingleton.getInstance();
LazySingletonone2=LazySingleton.getInstance();
System.out.println(one1==one2);
}
}
無論何種形式先要把結(jié)構(gòu)函數(shù)給私有化,否則就變成了“勤快漢”形式了;這名字是我瞎編的。
餓漢形式典型用法:Spring中IOC容器ApplictionContext,連接池.
懶漢形式典型用法:不知道啊。
餓漢形式?jīng)]缺點,最多也就在沒使用的時分,分配個內(nèi)存空間。
下面著重說說懶漢形式,所以來個分割線吧。
=================================
懶漢單例形式的線程安全
上面的懶漢形式有線程安全問題,便是多個線程在一起履行的時分,怎樣確保LazySingleton只被實例化了一次。
線程類:
publicclassExectorThreadimplementsRunnable{
@Overridepublicvoidrun(){
LazySimpleSingletonone=LazySimpleSingleton.getInstance();
System.out.println(Thread.currentThread().getName()+”:”+one);
}
}
單例類:
publicclassLazySimpleSingleton{privatestaticLazySimpleSingletonone=null;privateLazySimpleSingleton(){
}publicstaticLazySimpleSingletongetInstance(){if(one==null){
one=newLazySimpleSingleton();
}returnone;
}
}
測驗類:
publicclassLazyTest{publicstaticvoidmain(String[]args){
Threadt1=newThread(newExectorThread());
Threadt2=newThread(newExectorThread());
t1.start();
t2.start();
System.out.println(“end”);
}
}
第一個線程把one實例化完結(jié)之后,還沒有來得及刷新到內(nèi)存,第二個線程就把one讀入內(nèi)存,又進(jìn)行了一次實例化。
最簡略的辦法便是給實例化辦法getInstance()增加一個synchronized.
修改后代碼如下
publicclassLazySimpleSingleton{privatestaticLazySimpleSingletonone=null;privateLazySimpleSingleton(){
}publicstaticsynchronizedLazySimpleSingletongetInstance(){if(one==null){
one=newLazySimpleSingleton();
}returnone;
}
這種形式有一個功能問題;比如100個線程在一起調(diào)用getInstance()的時分,99個全部都堵塞在這個方位了,
包含one現(xiàn)已不是空值的時分,仍然在堵塞中;改造上面的代碼,讓現(xiàn)已實例化之后的線程不在堵塞。
1publicclassLazySimpleSingleton{23privatestaticLazySimpleSingletonone=null;45privateLazySimpleSingleton(){6}7publicstaticLazySimpleSingletongetInstance(){8//索前判別是否實例化了,實例化了就不用進(jìn)入synchronized中了9if(one==null){10synchronized(LazySimpleSingleton.class){11//上面one==null了,不代表此刻還是null12if(one==null){13one=newLazySimpleSingleton();14}15returnone;16}17}18returnone;19}20}
反射損壞單例
以餓漢單例的Demo為比如進(jìn)行改造。
1publicclassHungrySingleton{23privatestaticHungrySingletonone=newHungrySingleton();45privateHungrySingleton(){}67publicstaticHungrySingletongetInstance(){8returnone;9}1011publicstaticvoidmain(String[]args)throwsException{12HungrySingletonone1=HungrySingleton.getInstance();13Constructorconstructor=HungrySingleton.class.getDeclaredConstructor(null);14//強(qiáng)制拜訪結(jié)構(gòu)器,包含私有成員15constructor.setAccessible(true);16HungrySingletonone2=(HungrySingleton)constructor.newInstance();17System.out.println(one1==one2);18}19}
打印成果顯現(xiàn)false.說明被實例化了兩次;修改代碼如下。
publicclassHungrySingleton{privatestaticHungrySingletonone=newHungrySingleton();privateHungrySingleton(){if(one!=null){
thrownewRuntimeException(“現(xiàn)已實例化過了,本次實例化失敗”);
}}publicstaticHungrySingletongetInstance(){returnone;
}publicstaticvoidmain(String[]args)throwsException{
HungrySingletonone1=HungrySingleton.getInstance();
Constructorconstructor=HungrySingleton.class.getDeclaredConstructor(null);//強(qiáng)制拜訪結(jié)構(gòu)器,包含私有成員constructor.setAccessible(true);
HungrySingletonone2=(HungrySingleton)constructor.newInstance();
System.out.println(one1==one2);
}
}
打印成果:
序列化損壞單例形式
以餓漢形式為例:
publicclassSeriableSingletonimplementsSerializable{publicfinalstaticSeriableSingletonone=newSeriableSingleton();privateSeriableSingleton(){
}publicstaticSeriableSingletongetInstance(){returnone;
}
}
測驗類:
1publicclassSeriableSingletonTest{2publicstaticvoidmain(String[]args){3SeriableSingletons1=null;4SeriableSingletons2=SeriableSingleton.getInstance();56FileOutputStreamfos=null;7try{8fos=newFileOutputStream(“one.obj”);9ObjectOutputStreamoos=newObjectOutputStream(fos);10oos.writeObject(s2);11oos.flush();12oos.close();1314FileInputStreamfis=newFileInputStream(“one.obj”);15ObjectInputStreamois=newObjectInputStream(fis);16s1=(SeriableSingleton)ois.readObject();17ois.close();1819System.out.println(s1==s2);2021}catch(Exceptione){2223}24}25}
顯現(xiàn)成果是false.
這個問題很好辦,加一行代碼的事情。
1publicclassSeriableSingletonimplementsSerializable{2publicfinalstaticSeriableSingletonone=newSeriableSingleton();34privateSeriableSingleton(){5}67publicstaticSeriableSingletongetInstance(){8returnone;9}1011privateObjectreadResolve(){
12returnone;
13}14}
上面赤色便是增加的一個辦法。
這是一個古怪的現(xiàn)象,直接從源碼中找答案吧。
readObject()源碼
readObject0()源碼
privateObjectreadObject0(booleanunshared)throwsIOException{
…caseTC_OBJECT:returncheckResolve(readOrdinaryObject(unshared));
……..
}
上面代碼去除了一些無用代碼。
持續(xù)看readOrdinaryObject()源碼
privateObjectreadOrdinaryObject(booleanunshared)throwsIOException
{//判別是否有readResolve()辦法if(obj!=null&&handles.lookupException(passHandle)==null&&desc.hasReadResolveMethod())
{
Objectrep=desc.invokeReadResolve(obj);
}returnobj;
}
invokeReadResolve()源碼
ObjectinvokeReadResolve(Objectobj)throwsIOException,UnsupportedOperationException
{
……….if(readResolveMethod!=null){try{//利用反射調(diào)用readResolve()辦法returnreadResolveMethod.invoke(obj,(Object[])null);
}
}
}
由于JDK在readObject()時分,判別了有沒有readResolve()辦法,如果有的話就履行這個辦法,沒有就不履行了,咱們充分利用了這個特點,給他直接回來了一個one對象;
所以就不履行實例化了。其實這個當(dāng)?shù)卦趓eadObject()時分實例化了一次,只不過新創(chuàng)建的對象沒有被回來而已。
廣州天河區(qū)珠江新城富力盈力大廈北塔2706
020-38013166(網(wǎng)站咨詢專線)
400-001-5281 (售后服務(wù)熱線)
深圳市坂田十二橡樹莊園F1-7棟
Site/ http://www.szciya.com
E-mail/ itciya@vip.163.com
品牌服務(wù)專線:400-001-5281
長沙市天心區(qū)芙蓉中路三段398號新時空大廈5樓
聯(lián)系電話/ (+86 0731)88282200
品牌服務(wù)專線/ 400-966-8830
旗下運營網(wǎng)站:
Copyright ? 2016 廣州思洋文化傳播有限公司,保留所有權(quán)利。 粵ICP備09033321號