單例模式是創建型模式之一。
單例模式顧名思義是單例的,也就是只有一個實例化對象,這都來源於它的私有化構造函數。
單例模式特點:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例
單例模式的應用場景:Windows的Task Manager(任務管理器);網站的計數器; 多線程的線程池的設計; Web應用的配置對象的讀取(由於配置文件是共享的資源)。
單例模式的五種實現方法:
在看實現方法之前,要先了解一些java的知識:1、初始化順序依次是:(靜態變量、靜態初始化塊)–>(普通變量、初始化塊)–> 構造器;如果有父類,則順序是:父類static方法 –> 子類static方法 –> 父類構造方法- -> 子類構造方法 。
2、靜態變量特點:static變量值在類加載的時候分配空間,以后創建類對象的時候不會重新分配,后面根據需要是可以再次賦值的。公共性,就是說,一個類的靜態成員,它是屬於大伙的,所有的類對象共享的,不像成員變量是自己的。
1、餓漢模式
public class Singleton {
// 私有構造
private Singleton() {}
private static Singleton instance = new Singleton();
// 靜態工廠方法,方法沒有同步塊,所以效率高。
public static Singleton1 getInstance() {
return instance;
}
}
餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以后不再改變,所以天生是線程安全的。
2、懶漢模式
public class Singleton {
private static Singleton instance;
private Singleton (){}
//使用的同步鎖,降低了效率,但是在多線程可以防止創建多個實例
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
餓漢就是類一旦加載,就把單例初始化完成,保證getInstance的時候,單例是已經存在的了,
而懶漢比較懶,只有當調用getInstance的時候,才回去初始化這個單例。
3、雙重檢測模式
public class Singleton {
public static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronize (Singleton.class){
if( singleton == null ) {
singleton = new Singleton();
}
}
return singleton;
}
}
當兩個線程執行完第一個 singleton == null 后等待鎖, 其中一個線程獲得鎖並進入synchronize后,實例化了,然后退出釋放鎖,
另外一個線程獲得鎖,進入又想實例化,會判斷是否進行實例化了,如果存在,就不進行實例化了。
4、靜態內部類
public class Singleton {
// 靜態內部類LazyHolder
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
此方法既實現了線程安全,又避免了同步帶來的性能影響。
還有就是類似的靜態代碼塊實現:
public class Singleton{
// 私有構造
private Singleton() {}
private static Singleton single = null;
// 靜態代碼塊
static{
single = new Singleton();
}
public static Singleton getInstance() {
return single;
}
}
5、枚舉類
public class SingletonFactory {
// 內部枚舉類
private enum EnmuSingleton{
Singleton;
private Singleton singleton;
//枚舉類的構造方法在類加載是被實例化
private EnmuSingleton(){
singleton = new Singleton();
}
public Singleton getInstance(){
return singleton;
}
}
public static Singleton getInstance() {
return EnmuSingleton.Singleton.getInstance();
}
}
class Singleton{
public Singleton(){}
}
下面是一個單例模式使用的demo 餓漢模式
public class TestSingleton {
String name = null;
private TestSingleton() {
}
private static TestSingleton instance = new TestSingleton();
public static TestSingleton getInstance() {
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void print() {
System.out.println("the name is " + name);
}
public static void main(String[] args) {
// TODO 自動生成的方法存根
TestSingleton ts1 = TestSingleton.getInstance();
ts1.setName("12345");
TestSingleton ts2 = TestSingleton.getInstance();
ts2.setName("56789");
ts1.print();
ts2.print();
if(ts1 == ts2){
System.out.println("創建的是同一個實例");
}else{
System.out.println("創建的不是同一個實例");
}
}
}

