###【簡介】
單例模式(Singleton)保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
實現單例模式的一個最好的方法就是讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以創建,并且它可以提供一個訪問該實例的方法。
###【特點】
單例模式具有一下特點:
- 單例類只有一個實例
- 單例類必須自己創建自己的唯一實例
- 單例類必須給所有其他對象提供這一實例
###【分類】
主要的就是懶漢單例,餓漢單例
###【懶漢單例】
~~~
package Mode;
/**
* Java設計模式之單例模式
* @author SJF0115
*
*/
public class Singleton {
private static Singleton instance;
// 構造方法讓其private,這就堵死了外界利用new創建此類實例的可能
private Singleton() {
}
// 此方法是獲得本實例的唯一全局訪問點
public static Singleton GetInstance(){
// 若實例不存在,則new一個新實例,否則返回已有的實例
if(instance == null){
instance = new Singleton();
}
return instance;
}
/**
* @param args
*/
public static void main(String[] args) {
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if(s1 == s2){
System.out.println("兩個對象是相同的實例");
}
else{
System.out.println("兩個對象不是相同的實例");
}
}
}
~~~
這種寫法lazy loading很明顯,但是致命的是在多線程不能正常工作(多線程不安全)。
在類被加載的時候,唯一實例已經被創建。這個設計模式在Java中容易實現,在別的語言中難以實現。
###【餓漢單例】
~~~
package Mode;
/**
* Java設計模式之單例模式
* @author SJF0115
*
*/
public class Singleton {
// 類裝載時就實例化
private static Singleton instance = new Singleton();
// 構造方法讓其private,這就堵死了外界利用new創建此類實例的可能
private Singleton() {
}
// 此方法是獲得本實例的唯一全局訪問點
public static Singleton GetInstance(){
return instance;
}
/**
* @param args
*/
public static void main(String[] args) {
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if(s1 == s2){
System.out.println("兩個對象是相同的實例");
}
else{
System.out.println("兩個對象不是相同的實例");
}
}
}
~~~
這種方式基于classloder機制避免了多線程的同步問題,因此餓漢單例是線程安全的。
不過,instance在類裝載時就實例化,雖然導致類裝載的原因有很多種,在單例模式中大多數都是調用getInstance方法,?但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance顯然沒有達到lazy loading的效果。
###【懶漢單例(線程安全)】
~~~
package Mode;
/**
* Java設計模式之單例模式
* @author SJF0115
*
*/
public class Singleton {
private static Singleton instance;
// 構造方法讓其private,這就堵死了外界利用new創建此類實例的可能
private Singleton() {
}
// 此方法是獲得本實例的唯一全局訪問點
public static Singleton GetInstance(){
// 若實例不存在,則new一個新實例,否則返回已有的實例
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
/**
* @param args
*/
public static void main(String[] args) {
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if(s1 == s2){
System.out.println("兩個對象是相同的實例");
}
else{
System.out.println("兩個對象不是相同的實例");
}
}
}
~~~
有人可能會疑問,在GetInstnce方法中為什么會有兩次判斷if(instance == null)。
回答:
對于instance存在的情況,就直接返回。不需要考慮線程問題。當instance為null時,就需要我們考慮多線程帶來的問題。
假設當instance為null,并且同時有兩個線程調用GetInstance()方法,他們都可以通過第一重instance == null的判斷。
然后由于Synchronized機制,這兩個線程只有一個進入,另一個在外排隊等候,必須等先進入的線程結束之后,才能進入。
而此時如果沒有第二重instance == null 判斷,第一個線程進入后創建一個實例,第一個線程進入出來后,第二個線程終于等待結束,可以進入,
繼續又創建了一個實例,這沒有達到單例的目的。
- 前言
- [Hibernate開發之路](1)Hibernate配置
- [Hibernate開發之路](2)Hibernate問題
- [Hibernate開發之路](3)基礎配置
- [Hibernate開發之路](4)ID生成策略
- [Hibernate開發之路](5)聯合主鍵
- [設計模式實踐之路](1)單例模式
- [Java]UDP通信的簡單例子
- [Java]套接字地址InetAddress講解
- [Java開發之路](1)final關鍵字
- [Java開發之路](2)Java字符串
- [Java開發之路](3)Java常用類
- [Java開發之路](4)String、StringBuffer與StringBuilder詳解
- [Java開發之路](5)異常詳解
- [Java開發之路](6)File類的使用
- [Java開發之路](7)RandomAccessFile類詳解
- [Java開發之路](8)輸入流和輸出流
- [Java開發之路](9)對象序列化與反序列化
- [Java開發之路](10)DOM解析XML文檔
- [Java開發之路](11)SAX解析XML文檔
- [Java開發之路](12)JDOM和DOM4J解析XML文檔
- [Java開發之路](14)反射機制
- [Java開發之路](15)注解
- [Java開發之路](16)學習log4j日志
- [Java開發之路](18)關于Class.getResource和ClassLoader.getResource的路徑問題
- [Java開發之路](19)Long緩存問題
- [Java開發之路](20)try-with-resource 異常聲明
- [Java開發之路](21)Comparator與Comparable
- [Java]Java工程師成神之路
- [細說Java](1)圖說字符串的不變性
- [細說Java](2)Java中字符串為什么是不可變的
- [細說Java](3)創建字符串是使用" "還是構造函數?