單例模式
單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。
這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問其唯一的對(duì)象的方式,可以直接訪問,不需要實(shí)例化該類的對(duì)象。
例如:?jiǎn)卫J酱_保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、顯卡的驅(qū)動(dòng)程序?qū)ο蟪1辉O(shè)計(jì)成單例。這些應(yīng)用都或多或少具有資源管理器的功能。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。Windows 是多進(jìn)程多線程的,在操作一個(gè)文件的時(shí)候,就不可避免地出現(xiàn)多個(gè)進(jìn)程或線程同時(shí)操作一個(gè)文件的現(xiàn)象,所以所有文件的處理必須通過唯一的實(shí)例來進(jìn)行。
單例模式的特點(diǎn)
1、單例類只能有一個(gè)實(shí)例。
2、單例類必須自己創(chuàng)建自己的唯一實(shí)例。
3、單例類必須給所有其他對(duì)象提供這一實(shí)例。
為什么要用單例模式
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
關(guān)鍵
構(gòu)造函數(shù)應(yīng)該是私有的
例如
創(chuàng)建一個(gè) Singleton 類。
public class SingleObject {
//創(chuàng)建 SingleObject 的一個(gè)對(duì)象
private static SingleObject instance = new SingleObject();
//讓構(gòu)造函數(shù)為 private,這樣該類就不會(huì)被實(shí)例化
private SingleObject(){}
//獲取唯一可用的對(duì)象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
從 singleton 類獲取唯一的對(duì)象
public class SingletonPatternDemo {
public static void main(String[] args) {
//不合法的構(gòu)造函數(shù)
//編譯時(shí)錯(cuò)誤:構(gòu)造函數(shù) SingleObject() 是不可見的
//SingleObject object = new SingleObject();
//獲取唯一可用的對(duì)象
SingleObject object = SingleObject.getInstance();
//顯示消息
object.showMessage();
}
}
輸出結(jié)果
Hello World!
一.懶漢式單例(1)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Singleton通過將構(gòu)造方法限定為private避免了類在外部被實(shí)例化,在同一個(gè)虛擬機(jī)范圍內(nèi),Singleton的唯一實(shí)例只能通過getInstance()方法訪問。
懶漢式單例的實(shí)現(xiàn)沒有考慮線程安全問題,它是線程不安全的,并發(fā)環(huán)境下很可能出現(xiàn)多個(gè)Singleton實(shí)例,
二.懶漢式單例(2)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
這種方法能夠在多線程中很好的工作,但是,效率很低,99% 情況下不需要同步。
優(yōu)點(diǎn):第一次調(diào)用才初始化,避免內(nèi)存浪費(fèi)。
缺點(diǎn):必須加鎖 synchronized 才能保證單例,但加鎖會(huì)影響效率。
getInstance() 的性能對(duì)應(yīng)用程序不是很關(guān)鍵(該方法使用不太頻繁)
三.餓漢式單例
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
這種方式比較常用,但容易產(chǎn)生垃圾對(duì)象。
優(yōu)點(diǎn):沒有加鎖,執(zhí)行效率會(huì)提高。
缺點(diǎn):類加載時(shí)就初始化,浪費(fèi)內(nèi)存。
它基于 classloader 機(jī)制避免了多線程的同步問題,不過,instance 在類裝載時(shí)就實(shí)例化,雖然導(dǎo)致類裝載的原因有很多種,在單例模式中大多數(shù)都是調(diào)用 getInstance 方法, 但是也不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類裝載,這時(shí)候初始化 instance 顯然沒有達(dá)到 lazy loading 的效果。