【Java设计模式】单例模式
### 1. 概述
> 單例模式是確保某一個類中有且只有一個實例。
----------
### 2. 餓漢式單例
``` java
public class SingletonInstance {
private static SingletonInstance mInstance = new SingletonInstance();
// 默認私有構造方法
private SingletonInstance(){}
// 靜態工廠方法
public static SingletonInstance getInstance(){
return mInstance ;
}
}
```
在餓漢式單例中,靜態變量會在私有構造方法中初始化,這時候唯一的實例就被創建出來了,餓漢式主要使用到的是**空間換時間**的思想,在類還在加載的時候,對象實例便已經創建好了。
----------
### 3. 懶漢式單例
```java
public class SingletonInstance {
private static SingletonInstance mInstance = null;
// 私有默認構造方法
private SingletonInstance(){}
// 靜態工廠方法
public static synchronized SingletonInstance getInstance(){
if(mInstance == null){
mInstance = new SingletonInstance();
}
return mInstance;
}
}
```
對于懶漢式單例的處理,使用了``synchronized``參數修飾工廠方法,用來在多線程環境中解決同步問題,懶漢式主要是使用到的是**時間換空間**的思想,在獲取實例的時候進行判斷,只有在需要的時候才去創建對象,節省內存空間,但是缺點就是實現的方式是線程安全的,這樣會降低訪問的速度。
----------
### 4. 雙重加鎖單例
```java
public class SingletonInstance {
private volatile static SingletonInstance mInstance = null;
private SingletonInstance(){}
public static SingletonInstance getInstance(){
//先檢查實例是否存在,如果不存在才進入下面的同步塊
if(mInstance == null){
//同步塊,線程安全的創建實例
synchronized (SingletonInstance .class) {
//再次檢查實例是否存在,如果不存在才真正的創建實例
if(mInstance == null){
mInstance = new SingletonInstance ();
}
}
}
return mInstance;
}
}
```
雙重加鎖機制指的是,在每次進入``getInstance``方法先不同步,而是進入方法后,先檢查實例是否存在,如果不存在才進行下面的同步塊,這屬于第一重檢查,進入同步塊過后再檢查實例是否存在,如果不存在,就在同步的情況下創建一個新的實例,這屬于第二重檢查。這樣便只需要同步一次,并減少了在多次同步情況下進行判斷浪費的時間。
這種實現方式會使用到**volatile**關鍵字,意思是被**volatile**修飾的變量的值,不會被本地線程緩存,所有對該變量的讀寫都是直接操作共享內存,從而保證線程正確的處理該變量。
> **volatile**關鍵字在**JDK5**之前的版本中加鎖失敗,注意之。而且**volatile**關鍵字會屏蔽掉虛擬機中的一些必要的代碼優化,因此雖然能實現雙重檢查加鎖機制的單例,但并不建議大量采用。
那有什么方案可以既能達到延遲加載,又能實現線程安全的目的呢?
-----
### 5. Lazy Initialization Holder Class模式
```java
public class SingletonInstance {
private SingletonInstance(){}
/**
* 類級的內部類的實例與外部類的實例沒有綁定關系,而且只有被調用到時才會裝載
*/
private static class SingletonHolder{
/**
* 靜態初始化,由JVM來保證線程安全
*/
private static SingletonInstance mInstance = new SingletonInstance();
}
public static SingletonInstance getInstance(){
return SingletonHolder.mInstance;
}
}
```
如果只是想簡單的實現線程安全的單例,可以使用之前的**餓漢式**方式。但是缺點就是會在類裝載的時候初始化對象,造成空間的浪費。
那么只要解決了類加載時自動初始化對象的問題,便可以解決問題。因此可以采用類級內部類的方式去實現,這樣的話,只有在需要的時候才會創建對象實例,也達到了延遲加載和線程安全的目的。
從實現過程來看,但調用`getInstance`方法時,它會讀取`SingletonHolder.mInstance`,從而初始化,在這個類被裝載的時候,也會初始化靜態成員,而由于靜態域的特性,只會初始化一次,并且由JVM來保證線程安全。
>- 什么是類級內部類?
被`static`修飾的成員內部類才是類級內部類,如果沒有被`static`修飾則被稱為對象內部類,而且類級內部類與外部類對象不存在依賴關系,只有在第一次使用的時候才會被調用。
>- 多線程默認同步鎖知識?
在多線程開發中,我們主要使用`synchronized`來對互斥鎖進行同步控制,但是某些情況下JVM已經為我們進行了同步控制了,主要有:
1. 靜態初始化方法初始化數據時;
2. 訪問`final`字段時;
3. 在創建線程之前創建對象時;
4. 線程可以看見要處理的對象時;
----------
### 6. 枚舉式單例
```java
public enum SingletonInstace{
// 定義一個枚舉元素,它代表了一個實例
mInstance;
// 單例的操作
public void singletonOperation(){
}
}
```
使用枚舉的方式既使得代碼簡潔,而且也由JVM來保證序列化機制,防止多次實例化,是最佳的實現單例的方式。
轉載于:https://www.cnblogs.com/dennisac/p/4734868.html
總結
以上是生活随笔為你收集整理的【Java设计模式】单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .net dataGridView当鼠标
- 下一篇: Java基础08 继承