單例模式
單例模式(Singleton Pattern)是指確保一個類在任何情況下都絕對持有一個實體,并提供一個全域訪問點,
餓漢式單例模式
就是在類加載的時候就立即初始化,并且創建單例物件,絕對的執行緒安全
public class HungrySingleton {
//private static final HungrySingleton hungrySingleton = new HungrySingleton();
//靜態代碼塊
private static final HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
由于不加鎖,執行效率較高,
但在類加載的時候就已經實體化,不管用不用,都在占用記憶體,造成資源浪費,
懶漢式單例模式
就是在外部類呼叫的時候才會初始化,
public class LazySingleton {
private static LazySingleton lazy = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
//單執行緒安全
if(lazy==null) {
lazy = new LazySingleton();
}
return lazy;
}
}
該方法僅在單執行緒下執行緒安全,
做一點優化:
public synchronized static LazySingleton getInstance() {
if (lazy == null) {
lazy = new LazySingleton();
}
return lazy;
}
加synchronized后讓方法變為同步方法,實作在多執行緒下的執行緒安全,但仍存在問題,
因為每次呼叫方法獲取實體都會進行加鎖,如果執行緒過多就會影響效率,
再做一點優化:
/**
* 雙重檢查鎖的單例模式
* @return
*/
public static LazySingleton getInstance() {
if(lazy==null) {
synchronized(LazySingleton.class) {
if(lazy==null) {
lazy=new LazySingleton();
}
}
}
return lazy;
}
采用雙重判斷并加鎖機制來實作多執行緒下執行緒安全,
但這樣還是使用了synchronized關鍵字,總歸要上鎖,對程式性能還是存在一定的影響,
用內部類來實作單例模式
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {}
public static final LazyInnerClassSingleton getInstance() {
//再回傳結果之前,一定會先加載內部類
return LazyHolder.LAZY;
}
//默認不加載
private static class LazyHolder{
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
這個形式兼顧了餓漢式模式的記憶體浪費問題和synchronized的性能問題,
這樣就完美了嗎?
當然不是,單例模式的建構式除了加private關鍵字外,沒有其他任何處理,嘗試使用反射來呼叫其建構式,
public static void main(String[] args) {
try {
Class<?> clazz = LazyInnerClassSingleton.class;
//通過反射獲取私有的構造方法
Constructor<?> c = clazz.getDeclaredConstructor(null);
//強制訪問
c.setAccessible(true);
//暴力初始化
Object o1 = c.newInstance();
Object o2 = c.newInstance();
System.out.println(o1==o2);
}catch(Exception e) {
e.printStackTrace();
}
}
結果列印為false,這并不是單例模式希望看到的,對原來的建構式再做一些限制,一旦出現多次重復創建,則直接拋出例外,
private LazyInnerClassSingleton() {
if(LazyHolder.LAZY!=null) {
throw new RuntimeException("不允許創建多個實體");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/208530.html
標籤:其他
