有時候我們需要使用乙個實用類a,這個類a專門提供一些公共功能供別人呼叫,而本身並不會處理業務邏輯。由於類a會被許多類乃至執行緒呼叫,假設我們的程式非常龐大,在執行的過程中,會訪問這個類a100次,為了呼叫類a的方法,需要先建立a的物件,a a = new a()。這種方法在對a的訪問量較少的情況下沒問題,但是像我們這種情況,就會建立100個類a的例項,這100個例項是要占用記憶體的,從這種角度來說,就造成了大量不必要的開銷。而單例模式,在整個程式生命週期中,只有乙個例項,這樣就不會造成不必要的記憶體消耗。
為了讓整個生命週期內只有乙個例項,我們可以這樣做:
public
class
singleton
public
static singleton getinstance
() return ssingleton; }}
上述做法好像沒啥問題,由於msingleton是靜態的,因此能夠保證程式執行過程中只存在乙個例項。但是針對多執行緒情況,就可能有問題,比如有2個執行緒同時併發呼叫getinstance方法,並且同時執行到了line a,這個時候還是會各自new乙個物件出來,也就是說,存在了兩個例項,這違背了單例模式的概念,下面我們改進一下:
public
class
singleton
public
static singleton getinstance
() return ssingleton; } }}
上述做法的確是沒啥問題了,getinstance方法中對singleton.class加鎖,可以保證同一時刻只有乙個執行緒能夠進入getinstance方法。現在考慮一種情況,還是我們的比較龐大的工程,在某個**的時刻,我們需要訪問singleton物件100次,注意是高併發下的同時訪問,會是什麼情形呢?大概是這樣的:100個執行緒進入getinstance方法以後開始搶msingleton的所有權,這個時候,有乙個執行緒獲得了鎖,然後順利地得到了singleton例項,接著會是什麼情形呢?應該是這樣的:剩下99個執行緒開始搶
msingleton的所有權,一直這樣類推下去,可能有乙個執行緒運氣比較差,搶了100次才搶到鎖,程式的表現可能是這樣的:這個運氣差的執行緒被阻塞在getinstance方法中,遲遲無法返回,如果需要返回資料給ui的話,那麼ui將遲遲不會得到更新。
我們需要看一下上述**,真的需要每次進入getinstance方法都要獲得鎖嗎?其實不是的,整個singleton類中,對msingleton進行訪問的地方分為兩類:讀和寫,而且僅當msingleton為null的時候才會寫,msingleton一旦建立完畢,後面就只剩下讀操作了,再怎麼高併發也沒什麼關係了,反正msingleton已經是現成的,直接讀就可以了,看如下採用double-check機制的改進**:
public
class
singleton
public
static singleton getinstance
() } return ssingleton; }}
上述**近乎完美,可以滿足幾乎所有場合(採用反射和類載入器另當別論)。上述**的好處在於:第一次建立例項的時候會同步所有執行緒,以後有執行緒再想獲取singleton的例項就不需要進行同步,直接返回例項即可。還有double-check的意義在於:假設現在有2個執行緒a和b同時進入了getinstance方法,執行緒a執行到line a行,執行緒b執行到line b行,由於b執行緒還沒有初始化完畢,ssingleton還是null,於是執行緒a通過了ssingleton==null的判斷,並且往下執行,碰巧,當執行緒a執行到line c的時候,執行緒b初始化完畢了,然後執行緒b返回,注意,如果沒有double-check,這個時候執行緒a就執行到了line b,就會再次初始化
ssingleton,這個時候singleton實際上被new了兩次,已經不算完全意義上的單例了,而有了double-check,就會再進行一次為null的判斷,由於b執行緒已經初始化了ssingleton,所以a執行緒就不會再次初始化ssingleton。
public
class
singleton
private
static
class
instanceholder
public
static singleton getinstance
()}
就目前來看,dcl和靜態內部類單例模式是高併發場合首選的單例實現方式,在一些對併發要求不高的場合,我們也可以採用其他簡單的寫法,要做到具體情況具體分析,選擇適合的單例模式也是很有必要的,而不是一味地去追求高併發。
有時候我們需要使用乙個實用類a,這個類a專門提供一些公共功能供別人呼叫,而本身並不會處理業務邏輯。由於類a會被許多類乃至執行緒呼叫,假設我們的程式非常龐大,在執行的過程中,會訪問這個類a100次,為了呼叫類a的方法,需要先建立a的物件,a a = new a()。這種方法在對a的訪問量較少的情況下沒問題,但是像我們這種情況,就會建立100個類a的例項,這100個例項是要占用記憶體的,從這種角度來說,就造成了大量不必要的開銷。而單例模式,在整個程式生命週期中,只有乙個例項,這樣就不會造成不必要的記憶體消耗。
為了讓整個生命週期內只有乙個例項,我們可以這樣做:
public
class
singleton
public
static singleton getinstance
() return ssingleton; }}
上述做法好像沒啥問題,由於msingleton是靜態的,因此能夠保證程式執行過程中只存在乙個例項。但是針對多執行緒情況,就可能有問題,比如有2個執行緒同時併發呼叫getinstance方法,並且同時執行到了line a,這個時候還是會各自new乙個物件出來,也就是說,存在了兩個例項,這違背了單例模式的概念,下面我們改進一下:
public
class
singleton
public
static singleton getinstance
() return ssingleton; } }}
上述做法的確是沒啥問題了,getinstance方法中對singleton.class加鎖,可以保證同一時刻只有乙個執行緒能夠進入getinstance方法。現在考慮一種情況,還是我們的比較龐大的工程,在某個**的時刻,我們需要訪問singleton物件100次,注意是高併發下的同時訪問,會是什麼情形呢?大概是這樣的:100個執行緒進入getinstance方法以後開始搶msingleton的所有權,這個時候,有乙個執行緒獲得了鎖,然後順利地得到了singleton例項,接著會是什麼情形呢?應該是這樣的:剩下99個執行緒開始搶
msingleton的所有權,一直這樣類推下去,可能有乙個執行緒運氣比較差,搶了100次才搶到鎖,程式的表現可能是這樣的:這個運氣差的執行緒被阻塞在getinstance方法中,遲遲無法返回,如果需要返回資料給ui的話,那麼ui將遲遲不會得到更新。
我們需要看一下上述**,真的需要每次進入getinstance方法都要獲得鎖嗎?其實不是的,整個singleton類中,對msingleton進行訪問的地方分為兩類:讀和寫,而且僅當msingleton為null的時候才會寫,msingleton一旦建立完畢,後面就只剩下讀操作了,再怎麼高併發也沒什麼關係了,反正msingleton已經是現成的,直接讀就可以了,看如下採用double-check機制的改進**:
public
class
singleton
public
static singleton getinstance
() } return ssingleton; }}
上述**近乎完美,可以滿足幾乎所有場合(採用反射和類載入器另當別論)。上述**的好處在於:第一次建立例項的時候會同步所有執行緒,以後有執行緒再想獲取singleton的例項就不需要進行同步,直接返回例項即可。還有double-check的意義在於:假設現在有2個執行緒a和b同時進入了getinstance方法,執行緒a執行到line a行,執行緒b執行到line b行,由於b執行緒還沒有初始化完畢,ssingleton還是null,於是執行緒a通過了ssingleton==null的判斷,並且往下執行,碰巧,當執行緒a執行到line c的時候,執行緒b初始化完畢了,然後執行緒b返回,注意,如果沒有double-check,這個時候執行緒a就執行到了line b,就會再次初始化
ssingleton,這個時候singleton實際上被new了兩次,已經不算完全意義上的單例了,而有了double-check,就會再進行一次為null的判斷,由於b執行緒已經初始化了ssingleton,所以a執行緒就不會再次初始化ssingleton。
public
class
singleton
private
static
class
instanceholder
public
static singleton getinstance
()}
就目前來看,dcl和靜態內部類單例模式是高併發場合首選的單例實現方式,在一些對併發要求不高的場合,我們也可以採用其他簡單的寫法,要做到具體情況具體分析,選擇適合的單例模式也是很有必要的,而不是一味地去追求高併發。 設計模式 單例模式
單例模式 singleton pattern 是乙個比較簡單的模式,其定義如下 ensure a class has only one instance,and provide a golbal point of acess to it.確保某乙個類只有乙個例項,而且自行例項化並且向整個系統提供這個...
設計模式 單例模式
class testsingleton static public function instance return self testsingleton private function clone public function setsinvar sinvar public function ...
設計模式 單例模式
單例模式的目的是保證類在系統中只被例項化一次,由該唯一的例項來為系統提供服務.單例模式主要用於保證服務的統一,比如獲取統一的編號服務,模仿oracle的序列生成等.但單例的使用需要謹慎,特別是在需要作負載均衡的地方,因為這種程式級的單例模式實際上只能保證在乙個應用中為單例.如果被多個應用載入,還是會...