單例模式
單件:
獨(dú)一無二,他是利用單件模式構(gòu)造出來的,這個(gè)模式讓讓他在任何時(shí)刻都是只有一個(gè)對象,比如:如果注冊表設(shè)置的對象,不想這樣的對象有多個(gè)拷貝,就可以用單例模式,確保程序中使用的全局資源只有一份。
常常被用來管理共享資源,例如數(shù)據(jù)連接或者線程池
單例類擁有以下幾個(gè)要素:
- 私有構(gòu)造方法(保證客戶端無法去實(shí)例化該對象)
- 指向自己實(shí)例的私有靜態(tài)引用
- 以自己實(shí)例為返回值得靜態(tài)的共有的方法
單例模式分類
A、懶漢單例模式:在第一次調(diào)用的時(shí)候?qū)嵗旧?,在并發(fā)環(huán)境下,可能出現(xiàn)多個(gè)本身對象。所以線程是不安全的
B、餓漢單例模式:在類初始化時(shí),已經(jīng)自行實(shí)例化一個(gè)靜態(tài)對象,所以本身就是線程安全的
C、登記單例模式:通過一個(gè)專門的類對各單例模式的單一實(shí)例進(jìn)行管理和維護(hù)
詳細(xì)說明 (推薦餓漢式)
1.懶漢寫法:如果getInstance()的性能對應(yīng)用程序不是很關(guān)鍵,就什么都別做</p>
public class Singleton_1 {
public static void main(String[] args) {
Singleton_1 singleton_11 = Singleton_1.getSingleton_1();
Singleton_1 singleton_12 = Singleton_1.getSingleton_1();
System.out.println(singleton_11);
System.out.println(singleton_12);
}
private static Singleton_1 singleton_1 = null;
private Singleton_1(){}
public static Singleton_1 getSingleton_1(){
if (singleton_1 == null){
singleton_1 = new Singleton_1();
}
return singleton_1;
}
}
這種方式在多線程的情況下并不實(shí)用
下面測試:
/**
* Singleton 這種方式之適合單線程的狀態(tài)
* com.offer.demo.singleton.Singleton_1@5c25cea
* com.offer.demo.singleton.Singleton_1@3c13f478
* com.offer.demo.singleton.Singleton_1@3c13f478
*/
public class Singleton_1_Test {
public static void main(String[] args) {
Thread thead1 = new Thread(new Runnable() {
public void run() {
Singleton_1 singleton_1 =Singleton_1.getSingleton_1();
System.out.println(singleton_1);
}
});
Thread thead2 = new Thread(new Runnable() {
public void run() {
Singleton_1 singleton_2 =Singleton_1.getSingleton_1();
System.out.println(singleton_2);
}
});
Thread thead3 = new Thread(new Runnable() {
public void run() {
Singleton_1 singleton_3 =Singleton_1.getSingleton_1();
System.out.println(singleton_3);
}
});
thead1.start();
thead2.start();
thead3.start();
}
}
2.使用急切創(chuàng)建實(shí)例,而不是用延遲實(shí)例化的方法。這種方式也叫做餓漢式的單例模式
public class Singleton_2 {
public static void main(String[] args) {
Singleton_2 singleton_1 = Singleton_2.getSingleton_2();
Singleton_2 singleton_12 = Singleton_2.getSingleton_2();
System.out.println(singleton_1);
System.out.println(singleton_12);
}
private static Singleton_2 singleton_2 = new Singleton_2();
private Singleton_2(){}
public static Singleton_2 getSingleton_2(){
return singleton_2;
}
}
測試類:
/**
* 餓漢式適合多線程的情況
*
* com.offer.demo.singleton.Singleton_2@7bddc905
* com.offer.demo.singleton.Singleton_2@7bddc905
* com.offer.demo.singleton.Singleton_2@7bddc905
*/
public class Singleton_2_Test {
public static void main(String[] args) {
Thread thead1 = new Thread(new Runnable() {
public void run() {
Singleton_2 singleton_1 = Singleton_2.getSingleton_2();
System.out.println(singleton_1);
}
});
Thread thead2 = new Thread(new Runnable() {
public void run() {
Singleton_2 singleton_2 =Singleton_2.getSingleton_2();
System.out.println(singleton_2);
}
});
Thread thead3 = new Thread(new Runnable() {
public void run() {
Singleton_2 singleton_3 =Singleton_2.getSingleton_2();
System.out.println(singleton_3);
}
});
thead1.start();
thead2.start();
thead3.start();
}
}
3.用"雙重檢查加鎖",首先檢查是否實(shí)例已經(jīng)創(chuàng)建,如果尚未創(chuàng)建,才進(jìn)行同步,這里一來,只有第一次同步,這正是我們想要的。
1. public class SingletonTest3 {
2. //在靜態(tài)初始化器中創(chuàng)建單例,這段代碼保證了線程安全
3. private volatile static SingletonTest3 uniqueInstance;
4. //這里吧構(gòu)造器申明為私有的,只有自Singleton類內(nèi)才可以調(diào)用構(gòu)造器
5. private SingletonTest3(){}
6. //用getInstance方法實(shí)例化對象,并返回這個(gè)實(shí)例
7. public static SingletonTest3 getInstance(){
8. if(uniqueInstance==null){
9. synchronized (SingletonTest3.class){
10. if(uniqueInstance ==null){
11. uniqueInstance=new SingletonTest3();
12. }}}
13. //已經(jīng)有了實(shí)例了,直接使用它。
14. return uniqueInstance;
15. }
16. }
4.類加載的方式:延遲加載,線程安全,同步情況下效率高,不要進(jìn)行同步控制,實(shí)現(xiàn)簡單,不能防止反序列化
1. package designpattern.signleton;
2. /**
單例模式,類加載方式
8. */
9. public class SingletonTest4 {
10.
11. //這里吧構(gòu)造器申明為私有的,只有自Singleton類內(nèi)才可以調(diào)用構(gòu)造器
12. private SingletonTest4(){}
13.
14. //靜態(tài)內(nèi)部類,用于持有唯一的SingletonClass的實(shí)例
15. private static class OnlyInstance{
16. static private SingletonTest4 ONLY=new SingletonTest4();
17. }
18.
19. public static SingletonTest4 getInstance(){
20. return OnlyInstance.ONLY;
21. }
22. }
5.枚舉方式:立即加載,線程安全,實(shí)現(xiàn)簡單,防止反序列化。
1. public enum SingletonTest5 {
2.
3. INSRANCE;
4. public void f(){
5. }
6. }