單例模式可以避免多個(gè)對(duì)象對(duì)資源的消耗。
使用場(chǎng)景
當(dāng)某類只需一個(gè)對(duì)象的時(shí)候,如:IO的訪問;數(shù)據(jù)庫(kù)的訪問;圖片加載ImageLoader。
為什么ImageLoader要使用單例?
ImageLoader中又含有線程池、緩存、網(wǎng)絡(luò)請(qǐng)求等比較耗資源的對(duì)象,如果多次構(gòu)建,則會(huì)消耗過(guò)多資源。
實(shí)現(xiàn)方式
1. 聲明式:不推薦
private Test() {
}
public final static Test test = new Test();
優(yōu)點(diǎn):簡(jiǎn)單
缺點(diǎn):粗暴(系統(tǒng)啟動(dòng)時(shí)初始化,對(duì)節(jié)約資源不夠充分)
2. 懶漢式:不推薦
private Test() {
}
private static Test test;
public static synchronized Test getInstance() {
if (test == null) {
test = new Test();
}
return test;
}
優(yōu)點(diǎn):第一次使用時(shí)候初始化,保證線程安全
缺點(diǎn):每次使用都會(huì)同步,性能差
3. DCL(Double Check Lock)方式:可用,最常用的方式。
private Test() {
}
private static Test test;
public static Test getInstance() {
if (test == null) {
synchronized (Test.class) {
if (test == null) {
test = new Test();
}
}
}
return test;
}
優(yōu)點(diǎn):第一次使用時(shí)初始化,保證線程安全,避免不必要的同步
缺點(diǎn):高并發(fā)環(huán)境有缺陷
4. 靜態(tài)內(nèi)部類式:推薦。
private Test() {
}
public static Test getInstance() {
return InstanceHolder.test;
}
private static class InstanceHolder {
private final static Test test = new Test();
}
優(yōu)點(diǎn):延遲實(shí)例化,線程安全,單例唯一性。
缺點(diǎn):class個(gè)數(shù)增加。
5. 枚舉式
public enum Test {
Instance;
private int count;
public void countPlus(int plus) {
count += plus;
}
}
使用:Test.Instance.countPlus(3);
優(yōu)點(diǎn):線程安全,絕對(duì)唯一性(上述的幾種方式,在反序列化情況下會(huì)重新創(chuàng)建對(duì)象)。
缺點(diǎn):沒有延遲加載。
6. 容器式
private static Map<String, Object> instanceMap = new HashMap<>();
public static void registerService(String key, Object instance) {
if (!instanceMap.containsKey(key)) {
instanceMap.put(key, instance);
}
}
public static Object getService(String key) {
return instanceMap.get(key);
}
系統(tǒng)啟動(dòng)時(shí),將多種單例注入容器,使用時(shí)取出。
總結(jié)
單例的核心都是將構(gòu)造函數(shù)私有化,通過(guò)靜態(tài)方法獲取唯一實(shí)例,盡量節(jié)約資源提高性能,保證線程安全,防止反序列化導(dǎo)致重新實(shí)例化。