23種設(shè)計(jì)模式之單例模式
單例模式分為: 餓漢式 懶漢式 雙重鎖懶漢式 靜態(tài)懶漢式 靜態(tài)內(nèi)部類懶漢式 枚舉懶漢式
單例模式餓漢式
class SingletonTest01{
public static void main(String [] args){
//測(cè)試
Singleton inSingleton = Singleton.getInstance();
Singleton inSingleton2 = Singleton.getInstance();
System.out.println(inSingleton == inSingleton2);//true
System.out.println(inSingleton.hashCode());//hashCode相同
System.out.println(inSingleton2.hashCode());
}
}
class Singleton{
//1.構(gòu)造器私有化粱玲,外部不能通過(guò)new來(lái)創(chuàng)建對(duì)象
private Singleton(){}
//2.本類內(nèi)部創(chuàng)建對(duì)象實(shí)例在類加載的時(shí)候就會(huì)被創(chuàng)建,這里使用final是保證線程安全,final不可變對(duì)象
private final static Singleton instance = new Singleton();
//3.提供一個(gè)公有的靜態(tài)方法,返回實(shí)例對(duì)象印颤,通過(guò)調(diào)用方法來(lái)返回實(shí)例對(duì)象
public static Singleton getInstance() {
return instance;
}
}
//輸出
true
366712642
366712642
結(jié)論:
構(gòu)造器私有化,外部不能通過(guò)new來(lái)實(shí)例化對(duì)象穿肄,通過(guò)getInstance方法來(lái)創(chuàng)建對(duì)象
優(yōu)點(diǎn):線程安全,以空間換取時(shí)間效率高
缺點(diǎn):在類加載時(shí)對(duì)象被創(chuàng)建年局,會(huì)占用內(nèi)存
單例模式懶漢式
class SingletonTest02{
public static void main(String [] args){
// 測(cè)試
Singleton inSingleton = Singleton.getInstance();
Singleton inSingleton2 = Singleton.getInstance();
System.out.println(inSingleton == inSingleton2);// true
System.out.println(inSingleton.hashCode());// hashCode相同
System.out.println(inSingleton2.hashCode());
}
}
class Singleton{
//聲明一個(gè)對(duì)象
private static Singleton instance;
//構(gòu)造器私有化,外部不能通過(guò)new來(lái)創(chuàng)建對(duì)象
private Singleton(){}
//提供一個(gè)靜態(tài)的公有方法咸产,使用synchronize修飾加入同步處理的代碼矢否,線程安全
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
//輸出
true
366712642
366712642
結(jié)論:
缺點(diǎn):效率低,每個(gè)類在得到類的實(shí)例時(shí)候脑溢,執(zhí)行g(shù)etInstance()方法都要進(jìn)行同步僵朗。
優(yōu)點(diǎn):線程安全。
單例模式雙重檢查
class SingletonTest06{
public static void main(String [] args){
//測(cè)試
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2);// true
System.out.println(instance.hashCode());// hashCode相同
System.out.println(instance2.hashCode());
}
}
//懶漢式(線程安全同步方法)
class Singleton{
//采用volatile修飾變量防止重序
private static volatile Singleton instance;
private Singleton(){}
//提供一個(gè)靜態(tài)的公有方法屑彻,加入雙重代碼檢查验庙,解決線程安全問(wèn)題,同時(shí)解決懶加載問(wèn)題
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
//輸出
true
366712642
366712642
結(jié)論:
該單例模式采用volatile社牲、synchronized 進(jìn)行雙重檢查粪薛,防止了因?yàn)槎嗑€程問(wèn)題產(chǎn)生的重序难审。
很好的解決了線程安全性的問(wèn)題蝶防,創(chuàng)建對(duì)象的時(shí)候?qū)崿F(xiàn)了懶加載效果,當(dāng)需要用到時(shí)返回instance創(chuàng)建實(shí)例。
單例模式靜態(tài)內(nèi)部類
class SingletonTest7{
public static void main(String [] args){
//測(cè)試
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2);// true
System.out.println(instance.hashCode());// hashCode相同
System.out.println(instance2.hashCode());
}
}
class Singleton{
private Singleton(){}
//靜態(tài)內(nèi)部類淮椰,該類中有一個(gè)靜態(tài)屬性
private static class SingletonInstance{
//靜態(tài)內(nèi)部類可訪問(wèn)外部類的特性
private static final Singleton INSTANCE = new Singleton();
}
//提供一個(gè)靜態(tài)公共方法,直接返回SingletonInstance.INSTANCE
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
//輸出
true
366712642
366712642
結(jié)論:
這種方式采用了類裝在的機(jī)制來(lái)保證初始化實(shí)例時(shí)只有一個(gè)線程鼠次,靜態(tài)內(nèi)部類方式在Singleton類被裝在時(shí)并不會(huì)立即實(shí)例化撵溃,而是在需要實(shí)例化時(shí),調(diào)用getInstance()方法掂咒,才會(huì)裝載SingletonInstance類腮敌,從而完成Singleton的實(shí)例化,類的靜態(tài)屬性只會(huì)在第一次加載類的時(shí)候初始化俏扩,所以在這里糜工,JVM幫助我們保證了線程的安全性,在類進(jìn)行初始化時(shí)录淡,別的線程是無(wú)法進(jìn)入的捌木。
避免了線程不安全,利用靜態(tài)內(nèi)部類特點(diǎn)實(shí)現(xiàn)延遲加載嫉戚,效率高刨裆。
單例模式枚舉的方式
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);//true
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
//枚舉實(shí)現(xiàn)單例模式
enum Singleton{
INSTANCE;//屬性
public void sayOK() {
System.out.println("ok");
}
}
//輸出
true
366712642
366712642
結(jié)論
借助JDK1.5種添加的枚舉來(lái)實(shí)現(xiàn)單例模式。
枚舉在java中與普通類一樣彬檀,都能擁有字段與方法帆啃,而且枚舉實(shí)例創(chuàng)建是線程安全的,在任何情況下窍帝,它都是一個(gè)單例努潘。不僅能避免多線程同步問(wèn)題,而
且還能防止反序列化重新創(chuàng)建新的對(duì)象坤学。