單例模式是23種設計模式之一,是比較簡單的一種設計模式,它的目的是無論調用多少次,都返回同一個對象,它的特點是構造器私有化。
它分為兩種結構,一種是懶漢式的,一種是餓漢式的,它們各有優缺點,我們先從餓漢式看起,代碼如下:
1
2
3
4
5
6
7
8
|
public class Single { private static Single single = new Single(); private Single() { } public Single getInstance() { return single; } } |
通過上面的程序可以看出來雖然我們加載同一個對象的目的確實達到了,但當程序被加載的時候就會創建single這個對象,當這個類有多個這樣的方法時,我們可能會用不到這個對象中大多數單例,就會造成對內存的浪費。所以就出現了懶漢式的單例模式,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Single { private static Single single = null ; private Single() { } public Single getInstance() { if (single== null ){ single = new Single(); } return single; } } |
這樣,只有當我們真正調用這個對象時它才會被new出來,但是這樣是存在問題的。
當上面的第二段代碼在第一次加載的時候有兩個線程對其進行了調用,則會產生兩個不同的對象,所以是線程不安全的,這時候就會想到給這個方法加個鎖,加鎖之后的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Single { private static Single single = null ; private Single() { } public synchronized Single getInstance() { if (single == null ) { single = new Single(); } return single; } } |
這樣做確實做到了線程安全,但是當加鎖這個方法里面要執行很多東西,調用這個方法花費的時間會很長,這樣對服務器來說是致命的,因為這個方法如果某個線程一直調用的話,其它的線程是沒有辦法調的,服務器就阻塞了,那么升級后的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Single { priate static Single single = null ; private Single() { } public Single getInstance() { if (single == null ) { synchronized (Single. class ) { single = new Single(); } } return single; } } |
仔細觀察以后發現這樣并沒有鎖住,當第一次同時有兩個線程到達getInstance()方法if判斷時,其中有一個肯定是阻塞的,當另外一個執行完以后,阻塞這個線程是不會再判斷是否為空的,還是會創建一個對象的,這樣又有多個對象被產生了,再對其進行升級,得到的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Single { private static Single single = null ; private Single() { } public Single getInstance() { if (single == null ) { synchronized (Single. class ) { if (single == null ) { single = new Single(); } } } return single; } } |
這樣就不會產生上面的問題,而且也只鎖一次,因為第二次再執行這個方法時,會跳過if判斷,直接返回single,不會再被鎖,執行效率也會很高。
但即使是這樣,也還是有問題的,因為我們不能確定在內存中是先給對象賦值,還是先創建了這個對象,所以第二個程序有可能得到的是初始化一半了的對象,在jdk1.5之后,我們可以用volatile這個關鍵字來避免這種情況,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Single { private static volatile Single single = null ; private Single() { } public Single getInstance() { if (single == null ) { synchronized (Single. class ) { if (single == null ) { single = new Single(); } } } return single; } } |
但是這種情況很少使用,我在這里只是為了學習一下,嘻嘻