單例模式特點(diǎn)
保證一個(gè)類只有一個(gè)實(shí)例,并且提供一個(gè)訪問該實(shí)例的全局訪問點(diǎn)
windows中的任務(wù)管理器
操作系統(tǒng)的文件系統(tǒng),一個(gè)操作系統(tǒng)只能有一個(gè)文件系統(tǒng)
servlet編程中,每個(gè)servlet也是單例
SpringMVC中,控制對象也是單例
Spring中的bean

單例模式類圖
單例模式分類
餓漢式
特點(diǎn):減少系統(tǒng)開銷
public class SingletonDemo {
//類初始化的時(shí)候立即加載(沒有延時(shí)加載的優(yōu)勢),由于加載類的時(shí)候天熱的線程安全
private static final SingletonDemo singleDemo = new SingletonDemo();
//私有化構(gòu)造器
private SingletonDemo() {
}
//方法沒有同步,調(diào)用效率高
public static SingletonDemo getInstance(){
return singleDemo;
}
}
懶漢式
懶漢式普通實(shí)現(xiàn)
特點(diǎn):真正用的時(shí)候加載,資源的利用率高,但是每次調(diào)用的時(shí)候需要同步,并發(fā)下效率低
public class SingletonDemo1 {
//調(diào)用的時(shí)候加載
private static SingletonDemo1 instance = null;
//私有化構(gòu)造器
private SingletonDemo1() {
}
//方法同步,調(diào)用效率低
//為什么加鎖:多線程下,不加鎖會(huì)產(chǎn)生多個(gè)實(shí)例
public static synchronized SingletonDemo1 getInstance() {
if (instance == null) {
instance = new SingletonDemo1();
}
return instance;
}
}
懶漢式靜態(tài)內(nèi)部類實(shí)現(xiàn)
特點(diǎn):
外部沒有static屬性不會(huì)餓漢式那樣立即加載對象
真正調(diào)用getInstance()時(shí),才會(huì)加載靜態(tài)內(nèi)部類.類加載時(shí)是線程安全的,static final保證內(nèi)存中實(shí)例唯一
兼具并發(fā)高效和延時(shí)加載的優(yōu)勢
public class SingletonDemo2 {
private static class singletonClass {
private static final SingletonDemo2 instance = new SingletonDemo2();
}
public static SingletonDemo2 getInstance() {
return singletonClass.instance;
}
private SingletonDemo2() {
}
}
懶漢式其他實(shí)現(xiàn)
雙重檢測鎖式(由于jvm底層內(nèi)部模型原因,偶爾會(huì)出問題,不建立使用)
枚舉單例(線程安全,調(diào)用效率高,不能延時(shí)加載)
反射和反序列化漏洞
反射漏洞
反射可以破解單例(不包含枚舉式)實(shí)現(xiàn)方式?。梢栽跇?gòu)造方法中手動(dòng)拋出異常控制)
//測試
public class Client {
public static void main(String[] args) throws Exception {
SingletonDemo2 demo = SingletonDemo2.getInstance();
SingletonDemo2 demo1 = SingletonDemo2.getInstance();
System.out.println(demo);
System.out.println(demo1);
Class<SingletonDemo2> singletonDemo2Class = (Class<SingletonDemo2>) Class.forName("singleton.SingletonDemo2");
Constructor<SingletonDemo2> constructor = singletonDemo2Class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonDemo2 demo2 = constructor.newInstance();
SingletonDemo2 demo3 = constructor.newInstance();
System.out.println(demo2);
System.out.println(demo3);
}
}
//SingletonDemo2類的構(gòu)造方法修改為
//私有化構(gòu)造器
private SingletonDemo2() {
if (singletonClass.instance != null) {
throw new RuntimeException();
}
}
反序列化
反序列化可以破解單例(不包含枚舉式)實(shí)現(xiàn)方式?。梢蕴砑觬eadResolve()方法)
public class Client {
public static void main(String[] args) throws Exception {
SingletonDemo2 demo = SingletonDemo2.getInstance();
SingletonDemo2 demo1 = SingletonDemo2.getInstance();
System.out.println(demo);
System.out.println(demo1);
FileOutputStream fileOutputStream = new FileOutputStream("/Users/wjk/Desktop/a.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(demo);
objectOutputStream.close();;
fileOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/wjk/Desktop/a.txt"));
SingletonDemo2 singletonDemo2 =(SingletonDemo2) objectInputStream.readObject();
System.out.println(singletonDemo2);
}
}
//SingletonDemo2類實(shí)現(xiàn)序列化添加readResolve()
private Object readResolve() throws ObjectStreamException{
return singletonClass.instance;
}
}