單例模式屬於創建型模式的一種,應用於保證一個類僅有一個實例的場景下,並且提供了一個訪問它的全局訪問點,如spring中的全局訪問點BeanFactory,spring下所有的bean都是單例。
單例模式的特點:從系統啟動到終止,整個過程只會產生一個實例。
單例模式常用寫法:懶漢式,餓漢式,注冊式,序列化式。
下面比較一下懶漢式和餓漢式:
懶漢式:默認不會實例化,什么時候用什么時候new。
public class Lazy{
private Lazy(){}
//默認不會實例化,什么時候用什么時候new
private static Lazy lazy=null;
public static synchronized Lazy getInstance(){
if(lazy==null){
lazy=new Lazy();
}
return lazy;
}
}
餓漢式:類加載的時候就實例化,並且創建單例對象。
public class Hungry{
private Hungry(){}
// 類加載的時候就實例化,並且創建單例對象
private static final Hungry hungry=new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
懶漢式和餓漢式區別:
實例化方面:懶漢式默認不會實例化,外部什么時候調用什么時候new。餓漢式在類加載的時候就實例化,並且創建單例對象。
線程安全方面:餓漢式線程安全 (在線程還沒出現之前就已經實例化了,因此餓漢式線程一定是安全的)。懶漢式線程不安全( 因為懶漢式加載是在使用時才會去new 實例的,那么你去new的時候是一個動態的過程,是放到方法中實現的,比如:public static synchronized Lazy getInstance(){ if(lazy==null){ lazy=new Lazy(); } 如果這個時候有多個線程訪問這個實例,這個時候實例還不存在,還在new,就會進入到方法中,有多少線程就會new出多少個實例。一個方法只能return一個實例,那最終return出哪個呢?是不是會覆蓋很多new的實例?這種情況當然也可以解決,那就是加同步鎖,避免這種情況發生) 。
執行效率上:餓漢式沒有加任何的鎖,因此執行效率比較高。懶漢式一般使用都會加同步鎖,效率比餓漢式差。
性能上:餓漢式在類加載的時候就初始化,不管你是否使用,它都實例化了,所以會占據空間,浪費內存。懶漢式什么時候需要什么時候實例化,相對來說不浪費內存。