單例模式是結(jié)構(gòu)最簡單的設(shè)計(jì)模式隘世,核心結(jié)構(gòu)只包含一個(gè)特殊類即單例類。通過單例模式可以確保系統(tǒng)中的一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問丘逸,從而方便對實(shí)例個(gè)數(shù)進(jìn)行控制浦徊,節(jié)約系統(tǒng)資源馏予。
單例模式的目的是保證系統(tǒng)中一個(gè)類有且只有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)盔性。
常見單例模式實(shí)現(xiàn):
1.餓漢式單例模式(在類加載時(shí)就已創(chuàng)建單例對象)
在類被加載時(shí)霞丧,靜態(tài)變量instance會(huì)被初始化,此時(shí)類的私有構(gòu)造函數(shù)會(huì)被調(diào)用纯出,創(chuàng)建單例類的唯一實(shí)例蚯妇。
餓漢式在類加載時(shí)就已實(shí)例化,無須考慮多線程訪問暂筝,但不能實(shí)現(xiàn)延遲加載箩言,不管用不用都會(huì)占用內(nèi)存。
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
2.雙重檢查加鎖的懶漢式單例(延遲加載焕襟,在調(diào)用時(shí)才會(huì)去實(shí)例化)
懶漢式單例類在第一次使用時(shí)創(chuàng)建陨收,無須一直占用系統(tǒng)資源,實(shí)現(xiàn)了延遲加載鸵赖,但出現(xiàn)多線程同時(shí)首次引用的幾率變得比較大务漩,需要通過雙重檢查加鎖等機(jī)制來控制,將導(dǎo)致系統(tǒng)性能受到一定影響它褪。
使用雙重檢查加鎖的懶漢式單例模式饵骨,需要在靜態(tài)成員變量instance之前增加修飾符volatile,被volatile修飾的成員變量可以確保多個(gè)線程都能正確處理茫打,但volatile關(guān)鍵字會(huì)屏蔽Java 虛擬機(jī)所做的一些代碼優(yōu)化居触。
public class LazySingleton {
private volatile static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
// 第一重檢查
if (instance == null) {
// 加鎖
synchronized (LazySingleton.class) {
// 第二重檢查
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
3.靜態(tài)內(nèi)部類單例模式(實(shí)現(xiàn)延遲加載,又可以保證線程安全老赤,不影響系統(tǒng)性能)
由于靜態(tài)單例對象沒有作為Singleton的成員變量直接實(shí)例化轮洋,因此類加載時(shí)不會(huì)實(shí)例化Singleton,第一次調(diào)用getInstance()時(shí)將加載內(nèi)部類HolderClass,在該內(nèi)部類中定義了一個(gè)static類型的變量instance, 此時(shí)會(huì)首先初始化這個(gè)成員變量抬旺,由java虛擬機(jī)來保證其線程安全性弊予,確保該成員變量只能初始化一次。 由于getInstance()方法沒有任何線程鎖定开财,因此其性能不會(huì)造成任何影響汉柒。
public class Singleton {
private Singleton() {
}
//靜態(tài)內(nèi)部類
public static class HolderClass{
private final static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return HolderClass.instance;
}
}
4.test
/**
* Created by ZhangCheng on ${currentDate:date('yyyy/MM/dd')}
*/
public class Test {
public static void main(String[] args) {
Singleton s1=Singleton.getInstance();
Singleton s2=Singleton.getInstance();
//引用數(shù)據(jù)類型:當(dāng)他們用(==)進(jìn)行比較的時(shí)候,比較的是他們在內(nèi)存中的存放地址(確切的說责鳍,是堆內(nèi)存地址)
if(s1==s2) {
System.out.println("實(shí)例為同一實(shí)例竭翠!");
}
}
}