單例如果考慮性能問題, 一般會選擇懶漢式延遲加載
這裏記錄一下線程安全的單例寫法
- 寫法一: DCL
public class MySingleton {
private static volatile MySingleton sInstance; // 防止指令亂序
private MySingleton() {}
public static MySingleton getInstance() {
if (sInstance == null) { // 鎖外校驗, 削弱加鎖導致的性能問題
synchronized (MySingleton.class) {
if (sInstance == null) { // 鎖中校驗, 確保只產生一個對象
sInstance = new MySingleton();
}
}
}
return sInstance;
}
}
- 寫法二: Holder
public class MySingleton {
private MySingleton() {}
private static class SingletonHolder { // 靜態類"主動使用"時才加載, 不同於餓漢式
private static final MySingleton INSTANCE = new MySingleton();
// 相當於加鎖雙重驗證 = final保證初始化完成 , static保證單例;
}
public static MySingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
不論是哪種單例模式,其實例始終同Application共存亡,務必需注意其內部持有的監聽或回調(addXxx,registXxx)造成的內存泄露
- 採用軟/弱引用避免這種泄露
- 在合適的時機清除監聽(如onDestroy)