單例模式哪些不得不說的場景

點擊上方「藍字」關(guān)注我們

0x01:單例模式被破壞
反射技術(shù)非常強大,可以通過
setAccessible()來修改構(gòu)造器,字段,方法的可見性。單例模式的構(gòu)造方法是私有的,如果將其可見性設(shè)為public,那么將無法控制對象的創(chuàng)建。
public?class?Singleton?{
private?static?Singleton?instance?=?new?Singleton();???
????private?Singleton()?{}?
????public?static?Singleton?getInstance()?{
????????return?instance;
????}
}
通過以下代碼,即可構(gòu)建兩個不同的對象
public?class?SingletonCmd?{
?public?static?void?main(String[]?args)?throws?Exception{
????????Singleton?singleton?=?Singleton.getInstance();
????????Constructor?constructor?=?Singleton.class.getDeclaredConstructor();
????????constructor.setAccessible(true);
????????Singleton?newSingleton??=?constructor.newInstance();
????????System.out.println(singleton.hashCode());
????????System.out.println(newSingleton.hashCode());
????}
}
另外,克隆、序列化都可能導(dǎo)致單例模式被破壞。
0x02:防止反射破壞單例模式
主要通過在單例對象里添加一個標(biāo)識位,在創(chuàng)建了一個時,改變該標(biāo)識位。
public?class?Singleton?{
??private?static??Boolean?flag?=?Boolean.FALSE;
??private?static?Singleton?singleton?=?null;
??private?Singleton()?{
??????if?(!flag)?{
??????????synchronized?(Singleton.class)?{
??????????????if(!flag){
??????????????????flag?=?true;
??????????????}else{
??????????????????throw?new?RuntimeException("正在破壞單例模式");?
??????????????}
??????????}
??????}?else?{
??????????throw?new?RuntimeException("正在破壞單例模式");
??????}
??}
??public?static?Singleton?getInstance()?{
??????if?(singleton?==?null)?{
??????????synchronized?(Singleton.class)?{
??????????????if?(singleton?==?null)?{
??????????????????singleton?=?new?Singleton();
??????????????}
??????????}
??????}
??????return?singleton;
??}
??public?static?void?main(String[]?args)?throws?Exception?{
???? Singleton?s1?=?Singleton.getInstance();
????? Class?c1?=?Singleton.class;
???? Constructor?constructor?=?c1.getDeclaredConstructor();
???? constructor.setAccessible(true);
???? Singleton?s2?=?constructor.newInstance();
???? System.out.println(s1?==?s2);
}
}
這種實現(xiàn)并不是非常嚴(yán)謹(jǐn),因為既然可以通過反射來獲取構(gòu)造函數(shù)來創(chuàng)建實例了,那么同樣可以通過反射來獲取到定義的flag,那么在利用反射調(diào)用構(gòu)造函數(shù)之前,先獲取到這個flag,將它值重置,那么再次調(diào)用構(gòu)造函數(shù)就不會受到限制了,那這樣實際上就沒有起到防止重復(fù)創(chuàng)建對象的效果。這個另外一個實現(xiàn)方案
public?class?Singleton?{
????private?static?ImmutableBoolean?flag?=?new?ImmutableBoolean();
????private?static?Singleton?singleton?=?null;
????private?Singleton()?{
????????if?(flag.getCount()?<=?0)?{
????????????synchronized?(Singleton.class)?{
????????????????if?(flag.getCount()?<=?0)?{
????????????????????flag.setCount();
????????????????}?else?{
????????????????????throw?new?RuntimeException("正在破壞單例模式1");
????????????????}
????????????}
????????}?else?{
????????????throw?new?RuntimeException("正在破壞單例模式2");
????????}
????}
????public?static?Singleton?getInstance()?{
????????if?(singleton?==?null)?{
????????????synchronized?(Singleton.class)?{
????????????????if?(singleton?==?null)?{
????????????????????singleton?=?new?Singleton();
????????????????}
????????????}
????????}
????????return?singleton;
????}
????private?static?class?ImmutableBoolean?{
????????private?static?int?count?=?0;
????????public?ImmutableBoolean()?{
????????}
????????public?void?setCount()?{
????????????synchronized?(Singleton.class)?{
????????????????if?(count?<=?0)?{
????????????????????count++;
????????????????}?else?{
????????????????????throw?new?RuntimeException("counterror");
????????????????}
????????????}
????????}
????????public?int?getCount()?{
????????????return?count;
????????}
????}
}
定義一個私有的內(nèi)部類,然后用這個內(nèi)部類的屬性來作為flag,這樣外面的其他類就獲取不到這個私有的內(nèi)部類,也就不能改變它的值了,從而保護了單例的實現(xiàn)。
參考:https://blog.csdn.net/shengfengwuying/article/details/89919386
掃碼二維碼
獲取更多精彩
Java樂園

評論
圖片
表情
