核心作用:
保證一個類只有一個實例,並且提供一個訪問該實例的全局訪問點。
實例:
1.Windows中的任務管理器 2.回收站……
優點:
只生成一個實例,減小了系統性能的開銷
五種單例模式的實現方式:
1、餓漢式(線程安全,調用效率高。但是,不能延時加載)
私有屬性static類變量 先初始化(new 新對象)
私有的構造器
開放的方法--->取對象(方法無同步)
public class Demo01 {
//類初始化時,立即加載這個對象。(沒有延時加載優勢)
//天然線程安全
private static Demo01 instance = new Demo01();
private Demo01(){}
//方法沒有同步,調用效率高
public static Demo01 getInstance(){
return instance;
}
}
2、懶漢式(線程安全,調用效率不高。但是,可以延時加載)
私有屬性static類變量 不用初始化
私有化構造器
開放方法-->取對象 使用方法時才檢查初始化對象(new) (方法有同步)
public class Demo02 {
//類初始化時,不初始化這個對象。(延時加載優勢)
//天然線程安全
private static Demo02 instance ;
private Demo02(){}
//方法同步,調用效率不高
public static synchronized Demo02 getInstance(){
if(instance==null){
instance = new Demo02();
}
return instance;
}
}
3、雙重檢測鎖式(由於JVM底層內部模型原因,偶爾會出現問題,不建議使用)
將同步內容放到下方的if內部
public class Demo03 {
private Demo03(){}
private static Demo03 instance=null;
public static Demo03 getInstance() {
if (instance == null) {
Demo03 sc;
synchronized (Demo03.class) {
sc = instance;
if (sc == null) {
synchronized (Demo03.class) {
if(sc == null) {
sc = new Demo03();
}
}
instance = sc;
}
}
}
return instance;
}
}
4、靜態內部類式(線程安全,調用效率高,但是,可以延時加載)
外部類沒有static屬性,不會像餓漢式那樣立即加載對象
只有真正調用getInstance(),纔會加載靜態內部類。
public class Demo04 {
private static class SingleTonClassInstance{
private static final Demo04 instance = new Demo04();
}
public static Demo04 getInstance(){
return SingleTonClassInstance.instance;
}
private Demo04(){}
}
5、枚舉單例(線程安全,調用效率高,不能延時加載)
基於JVM實現的
可以天然防止反射和反序列化漏洞
public enum Demo05 {
//這個枚舉元素,本身就是單例對象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
……
}
}
需要延時加載:靜態內部類好於餓漢式
不需要延時加載:靜態內部類好於懶漢式
測試懶漢式單例模式(如何防止反射和反序列化漏洞):
public class Demo06 implements Serializable{
//類初始化時,不初始化這個對象。(延時加載優勢)
//天然線程安全
private static Demo06 instance ;
private Demo06(){
//通過這樣防止反射創建新的對象
if(instance!=null){
throw new RuntimeException();
}
}
//方法同步,調用效率不高
public static synchronized Demo06 getInstance(){
if(instance==null){
instance = new Demo06();
}
return instance;
}
//反序列化時,如果定義了readResolve()方法則直接返回方法指定對象。而不再單獨創建新的對象
private Object readResolve() throws ObjectStreamException{
return instance;
}
}