單例模式經(jīng)常都會(huì)看倾芝,但是什么時(shí)候 show me the code
簡單介紹
1.單例為保證安全,整個(gè)應(yīng)用只有一個(gè)實(shí)例箭跳,構(gòu)造方法需私有化,直接賦值對(duì)象加final
2.單例一般有懶漢式晨另、餓漢式、枚舉類等
3.單例一般需要防止反射谱姓、反序列化創(chuàng)建問題
餓漢式
安全借尿,啟動(dòng)即創(chuàng)建,占用空間屉来、性能
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
或靜態(tài)塊模式
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
static{
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton(){
}
public static HungryStaticSingleton getInstance(){
return hungrySingleton;
}
}
懶漢式
簡單的懶漢式
調(diào)用時(shí)創(chuàng)建路翻,需要鎖加載保證安全
public class LazySimpleSingleton {
private static LazySimpleSingleton lazySingleton = null;
private LazySimpleSingleton(){
}
public synchronized static LazySimpleSingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySimpleSingleton();
}
return lazySingleton;
}
}
double check
public class LazyDoubleCheckSingleton {
private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){
}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton == null){
synchronized(LazyDoubleCheckSingleton.class) {
if(lazyDoubleCheckSingleton == null) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
內(nèi)部類
內(nèi)部類調(diào)用創(chuàng)建,且不需要加鎖茄靠;推薦使用
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {
if(LazyHandler.instance != null){
throw new RuntimeException("不允許創(chuàng)建多個(gè)實(shí)例");
}
}
public static final LazyInnerClassSingleton getInstance() {
return LazyHandler.instance;
}
private static class LazyHandler {
private static final LazyInnerClassSingleton instance = new LazyInnerClassSingleton();
}
}
注冊(cè)式
枚舉類
枚舉類是由jdk來保證單例安全茂契,enum只會(huì)創(chuàng)建一次
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
容器式
/**
* 容器注冊(cè)式,spring中就是采用這種方法實(shí)現(xiàn)單例
*/
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<>();
public static Object getInstance(String className){
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try{
obj = Class.forName(className).newInstance();
ioc.put(className,obj);
}catch (Exception e){
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
}
ThreadLocal
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}
附單例破壞
反射將權(quán)限設(shè)置true強(qiáng)制創(chuàng)建private構(gòu)造器慨绳;枚舉類可以防止破壞
Class<?> clazz = LazyInnerClassSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
//強(qiáng)制訪問
c.setAccessible(true);
//暴力初始化
Object o1 = c.newInstance();
//調(diào)用了兩次構(gòu)造方法掉冶,相當(dāng)于new了兩次
//犯了原則性問題真竖,
Object o2 = c.newInstance();
System.out.println(o1 == o2); //false
反序列化讀寫破壞單例,重寫一個(gè)readResolve()可以防止反序列化
//反序列化時(shí)導(dǎo)致單例破壞
public class SeriableSingleton implements Serializable {
//序列化就是說把內(nèi)存中的狀態(tài)通過轉(zhuǎn)換成字節(jié)碼的形式
//從而轉(zhuǎn)換一個(gè)IO流厌小,寫入到其他地方(可以是磁盤恢共、網(wǎng)絡(luò)IO)
//內(nèi)存中狀態(tài)給永久保存下來了
//反序列化
//講已經(jīng)持久化的字節(jié)碼內(nèi)容,轉(zhuǎn)換為IO流
//通過IO流的讀取璧亚,進(jìn)而將讀取的內(nèi)容轉(zhuǎn)換為Java對(duì)象
//在轉(zhuǎn)換過程中會(huì)重新創(chuàng)建對(duì)象new
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
}
public static void main(String[] args) {
SeriableSingleton s1 = null;
SeriableSingleton s2 = SeriableSingleton.getInstance();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("SeriableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SeriableSingleton)ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2); //false
} catch (Exception e) {
e.printStackTrace();
}
}