#單例模式
---
###定義
>保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
>Singleton:負責創建Singleton類自己的唯一實例,并提供一個getInstance的方法,讓外部來訪問這個類的唯一實例。
* 餓漢式:
```
private static Singleton uniqueInstance = new Singleton();
```
* 懶漢式
```
private static Singleton uniqueInstance = null;
```
###功能
單例模式是用來保證這個類在運行期間只會被創建一個類實例,另外,單例模式還提供了一個全局唯一訪問這個類實例的訪問點,就是getInstance方法。
###范圍
Java里面實現的單例是一個虛擬機的范圍。因為裝載類的功能是虛擬機的,所以一個虛擬機在通過自己的ClassLoader裝載餓漢式實現單例類的時候就會創建一個類的實例。
懶漢式單例有延遲加載和緩存的思想
###優缺點
* 懶漢式是典型的時間換空間
* 餓漢式是典型的空間換時間
---
* 不加同步的懶漢式是線程不安全的。比如,有兩個線程,一個是線程A,一個是線程B,它們同時調用getInstance方法,就可能導致并發問題。
* 餓漢式是線程安全的,因為虛擬機保證只會裝載一次,在裝載類的時候是不會發生并發的。
---
如何實現懶漢式的線程安全?
加上synchronized即可
```
public static synchronized Singleton getInstance(){}
```
但這樣會降低整個訪問的速度,而且每次都要判斷。可以用雙重檢查加鎖。
雙重加鎖機制,指的是:并不是每次進入getInstance方法都需要同步,而是先不同步,進入方法過后,先檢查實例是否存在,如果不存在才進入下面的同步塊,這是第一重檢查。進入同步塊后,再次檢查實例是否存在,如果不存在,就在同步的情況下創建一個實例。這是第二重檢查。
雙重加鎖機制的實現會使用一個關鍵字volatile,它的意思是:被volatile修飾的變量的值,將不會被本地線程緩存,所有對該變量的讀寫都是直接操作共享內存,從而確保多個線程能正確的處理該變量。
```
/**
* 雙重檢查加鎖的單例模式
* @author dream
*
*/
public class Singleton {
/**
* 對保存實例的變量添加volitile的修飾
*/
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
//先檢查實例是否存在,如果不存在才進入下面的同步塊
if(instance == null){
//同步塊,線程安全的創建實例
synchronized (Singleton.class) {
//再次檢查實例是否存在,如果不存在才真正的創建實例
instance = new Singleton();
}
}
return instance;
}
}
```
###一種更好的單例實現方式
```
public class Singleton {
/**
* 類級的內部類,也就是靜態類的成員式內部類,該內部類的實例與外部類的實例
* 沒有綁定關系,而且只有被調用時才會裝載,從而實現了延遲加載
* @author dream
*
*/
private static class SingletonHolder{
/**
* 靜態初始化器,由JVM來保證線程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化構造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
```
根據《高效Java第二版》中的說法,單元素的枚舉類型已經成為實現Singleton的最佳方法。
```
package example6;
/**
* 使用枚舉來實現單例模式的示例
* @author dream
*
*/
public class Singleton {
/**
* 定義一個枚舉的元素,它就代表了Singleton的一個實例
*/
uniqueInstance;
/**
* 示意方法,單例可以有自己的操作
*/
public void singletonOperation(){
//功能樹立
}
}
```
---
###本質
控制實例數量
###何時選用單例模式
當需要控制一個類的實例只能有一個,而且客戶只能從一個全局訪問點訪問它時,可以選用單例模式,這些功能恰好是單例模式要解決的問題。
- JavaSE(Java基礎)
- Java基礎知識
- Java中的內存泄漏
- String源碼分析
- Java集合結構
- ArrayList源碼剖析
- HashMap源碼剖析
- Hashtable簡介
- Vector源碼剖析
- LinkedHashMap簡介
- LinkedList簡介
- JVM(Java虛擬機)
- JVM基礎知識
- JVM類加載機制
- Java內存區域與內存溢出
- 垃圾回收算法
- Java并發(JavaConcurrent)
- Java并發基礎知識
- 生產者和消費者問題
- Thread和Runnable實現多線程的區別
- 線程中斷
- 守護線程與阻塞線程的情況
- Synchronized
- 多線程環境中安全使用集合API
- 實現內存可見的兩種方法比較:加鎖和volatile變量
- 死鎖
- 可重入內置鎖
- 使用wait/notify/notifyAll實現線程間通信
- NIO
- 數據結構(DataStructure)
- 數組
- 棧和隊列
- Algorithm(算法)
- 排序
- 選擇排序
- 冒泡排序
- 快速排序
- 歸并排序
- 查找
- 順序查找
- 折半查找
- Network(網絡)
- TCP/UDP
- HTTP
- Socket
- OperatingSystem(操作系統)
- Linux系統的IPC
- android中常用設計模式
- 面向對象六大原則
- 單例模式
- Builder模式
- 原型模式
- 簡單工廠
- 策略模式
- 責任鏈模式
- 觀察者模式
- 代理模式
- 適配器模式
- 外觀模式
- Android(安卓面試點)
- Android基礎知識
- Android內存泄漏總結
- Handler內存泄漏分析及解決
- Android性能優化
- ListView詳解
- RecyclerView和ListView的異同
- AsyncTask源碼分析
- 插件化技術
- 自定義控件
- ANR問題
- Art和Dalvik的區別
- Android關于OOM的解決方案
- Fragment
- SurfaceView
- Android幾種進程
- APP啟動過程
- 圖片三級緩存
- Bitmap的分析與使用
- 熱修復的原理
- AIDL
- Binder機制
- Zygote和System進程的啟動過程
- Android中的MVC,MVP和MVVM
- MVP
- Android開機過程
- EventBus用法詳解
- 查漏補缺
- Git操作