單例模式一定要扛得住并發(fā)。

單例模式有很多版本,包括雙重檢查,靜態(tài)內(nèi)部類(lèi),枚舉,其他的寫(xiě)法也有,建議大家看深入淺出單實(shí)例SINGLETON設(shè)計(jì)模式。
餓漢單例的話(huà)太一勞永逸,如果你碰上了那種要使用很多資源的類(lèi)的單例,但是一時(shí)半會(huì)兒又用不上的情況,那么還是不要用了。我寫(xiě)的單例都是使用的時(shí)候才加載的那種,也就是所謂的懶漢式單例。
單例模式的特點(diǎn)總結(jié)為兩私有一公開(kāi),隨時(shí)注意靜態(tài)(我認(rèn)為是兩處?kù)o態(tài)),兩私有是指私有構(gòu)造方法,私有的指向自身的實(shí)例,一公開(kāi)是指公開(kāi)的對(duì)外獲取單例的方法,隨時(shí)注意靜態(tài)是指:因?yàn)闃?gòu)造方法私有,所以你不能通過(guò)創(chuàng)建實(shí)例來(lái)調(diào)用方法,那么就只有通過(guò)類(lèi)名來(lái)調(diào)用里面的靜態(tài)方法,記憶的鏈?zhǔn)剿季S是這樣的,獲取單例的方法必須靜態(tài),這個(gè)方法要調(diào)用指向單例的實(shí)例,由于靜態(tài)方法只能調(diào)用靜態(tài)方法和靜態(tài)變量,那么被調(diào)用的那個(gè)單例的實(shí)例也必須是靜態(tài)的(多注意枚舉那里)。
基本的模板
class Singleton {
private Singleton(){}
private static Singleton singleton = null;
public static Singleton getSingleton() {
return null;
}
}
具體的實(shí)現(xiàn)
/**
* Double check && volatile Edition
* 雙重檢查volatile版本
*/
class DoubleCheckSingleton {
private DoubleCheckSingleton(){}
private static volatile DoubleCheckSingleton INSTANCE = null;
public static DoubleCheckSingleton getSingleton() {
if (INSTANCE == null) {
synchronized (DoubleCheckSingleton.class) {
if (INSTANCE == null) {
INSTANCE = new DoubleCheckSingleton();
}
}
}
return INSTANCE;
}
}
/**
* Static inner class Edition
* 靜態(tài)內(nèi)部類(lèi)版本
*/
class InnerClassSingleton {
private InnerClassSingleton(){}
private static class SingletonHolder {
private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
public static InnerClassSingleton getSingleton() {
return SingletonHolder.INSTANCE;
}
}
/**
* Enum Edition
* 枚舉版本
*/
class EnumSingleton {
private EnumSingleton(){}
public static EnumSingleton getSingleton() {
return singleton.INSTANCE.getSingleton();
}
enum singleton {
INSTANCE;
private EnumSingleton singleton;
private singleton(){ singleton = new EnumSingleton();}
private EnumSingleton getSingleton(){return singleton;}
}
}
/**
* 測(cè)試線(xiàn)程,在這里更改使用的版本,雖然這很不軟件工程
*/
class SimpleThread implements Runnable {
@Override
public void run() {
System.out.println(DoubleCheckSingleton.getSingleton());
}
}
/**
* 測(cè)試主入口
*/
public class SingletonVersions {
public static void main(String[] args) {
SimpleThread simpleThread = new SimpleThread();
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(simpleThread);
thread.start();
}
}
}
不知道大家注意到了沒(méi)有,我這里這么多個(gè)類(lèi),就SingletonVersions是public的,而且這么多個(gè)代碼全在一個(gè)文件也就是SingletonVersions.java里面,沒(méi)錯(cuò),但是大家注意,訪(fǎng)問(wèn)權(quán)限,沒(méi)有寫(xiě)public的類(lèi)只具有包訪(fǎng)問(wèn)權(quán)限。一個(gè)java文件里面只準(zhǔn)存在一個(gè)public的類(lèi),但是還可以寫(xiě)其他的非public類(lèi),還可以寫(xiě)接口,枚舉,我經(jīng)常因?yàn)榇a很短,圖方便的話(huà)就寫(xiě)在一個(gè)類(lèi)里面了。
泛型單例
這個(gè)提的人很少,但是是有他的存在價(jià)值的,比如你有很多個(gè)工具類(lèi),都想用單例模式來(lái)創(chuàng)建唯一對(duì)象來(lái)減小開(kāi)銷(xiāo),那么寫(xiě)個(gè)泛型就是有必要了的。
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by Curry on 17/6/26.
*/
public class Singleton<T> {
/**
* 私有構(gòu)造函數(shù),在這里顯得表雞肋,沒(méi)有任何作用
* 但是處于對(duì)單例模式的尊重,要給全它定義中的,私有構(gòu)造函數(shù)、私有靜態(tài)自身實(shí)例,共有靜態(tài)的獲取單例的方法
*/
private Singleton() {
}
/**
* 私有,靜態(tài),并發(fā)哈希表,用于存儲(chǔ)所有的實(shí)例的唯一單例,而且其本身也是靜態(tài)唯一的
*/
private static ConcurrentHashMap<Class, Object> map = new ConcurrentHashMap<>();
/**
* 公開(kāi),靜態(tài),泛型的獲取對(duì)應(yīng)類(lèi)型的單例
*/
public static <T> T getDefault(Class<T> type) {
if (map.get(type) == null) {
synchronized (map) {
if (map.get(type) == null) {
try {
/**
* 這里利用反射,將私有的構(gòu)造方法改為共有的,用于創(chuàng)建實(shí)例,否則無(wú)法創(chuàng)建實(shí)例
*/
Constructor constructor = type.getDeclaredConstructor();
constructor.setAccessible(true);
map.put(type, constructor.newInstance());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
return (T)map.get(type);
}
/**
* 根據(jù)類(lèi)型移除存儲(chǔ)在哈希表中的單例
*/
public static <T> void removeSingleton(Class<T> type) {
map.remove(type);
}
}