2020-12-08——單例模式在JDK以及Spring原始碼中如何進行串聯
建立型模式
目錄
1、單例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。許多時候整個系統只需要擁有一個的全域性物件,這樣有利於我們協調系統整體的行為。比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程式中的其他物件再通過這個單例物件獲取這些配置資訊。這種方式簡化了在複雜環境下的配置管理。
意圖:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
主要解決:一個全域性使用的類頻繁地建立與銷燬。
何時使用:當您想控制例項數目,節省系統資源的時候。
如何解決:判斷系統是否已經有這個單例,如果有則返回,如果沒有則建立。
關鍵程式碼:建構函式是私有的。
1.1 單例模式UML圖
1.2 日常生活中看單例模式
- 1、一個班級只有一個班主任。
- 2、Windows 是多程式多執行緒的,在操作一個檔案的時候,就不可避免地出現多個程式或執行緒同時操作一個檔案的現象,所以所有檔案的處理必須通過唯一的例項來進行。
- 3、一些裝置管理器常常設計為單例模式,比如一個電腦有兩臺印表機,在輸出的時候就要處理不能兩臺印表機列印同一個檔案。
1.3 使用場景
- 1、要求生產唯一序列號。
- 2、WEB 中的計數器,不用每次重新整理都在資料庫里加一次,用單例先快取起來。
- 3、建立的一個物件需要消耗的資源過多,比如 I/O 與資料庫的連線等。
注意事項:getInstance() 方法中需要使用同步鎖 synchronized (Singleton.class) 防止多執行緒同時進入造成 instance 被多次例項化。
1.4 具體例子
1.4.1 背景
- 在企業網站後臺系統中,一般會將網站統計單元進行獨立設計,比如登入人數的統計、IP數量的計數等。在這類需要完成全域性統計的過程中,就會用到單例模式,即整個系統只需要擁有一個計數的全域性物件。
- 在網站登入這個高併發場景下,由這個全域性物件負責統計當前網站的登入人數、IP等,即節約了網站伺服器的資源,又能保證計數的準確性。
1.4.2 網站計數的單例實現
實現單例模式有多種寫法,這裡我們只列舉其中最常用的三種實現方式,且考慮到網站登入高併發場景下,將重點關注多執行緒環境下的安全問題。
登入執行緒的實現:我們先建立一個登入執行緒類,用於登入及登入成功後呼叫單例物件進行計數。
/**
* 單例模式的應用--登入執行緒
*
* @author zhuhuix
* @date 2020-06-01
*/
public class Login implements Runnable {
// 登入名稱
private String loginName;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
@Override
public void run() {
// TODO
// 登入成功後呼叫單例物件進行計數
}
}
主程式的實現:編寫一個主程式,利用多執行緒技術模擬10個使用者併發登入,完成登入後輸出登入人次計數。
/**
* 單例模式--主程式
*
* @author zhuhuix
* @date 2020-06-01
*/
public class App {
public final static int num = 10;
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
Login login = new Login();
login.setLoginName("" + String.format("%2s", (i + 1)) + "號使用者");
threads[i] = new Thread(login);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
// TODO
// 呼叫單例物件輸出登入人數統計
}
1.4.2.1 餓漢模式
- 在程式啟動之初就進行建立( 不管三七二十一,先建立出來再說)。
- 天生的執行緒安全。
- 無論程式中是否用到該單例類都會存在。
/**
* 餓漢式單例模式
*
* @author zhuhuix
* @date 2020-06-01
*/
public class SimpleSingleton implements Serializable {
// 單例物件
private static final SimpleSingleton APP_INSTANCE = new SimpleSingleton();
// 計數器
private AtomicLong count = new AtomicLong(0);
// 單例模式必須保證預設構造方法為私有型別
private SimpleSingleton() {
}
public static SimpleSingleton getInstance() {
return APP_INSTANCE;
}
public AtomicLong getCount() {
return count;
}
public void setCount() {
count.addAndGet(1);
}
}
我們將餓漢模式的單例物件加入進登入執行緒及主程式中進行測試:
/**
* 單例模式的應用--登入執行緒
*
* @author zhuhuix
* @date 2020-06-01
*/
public class Login implements Runnable {
// 登入名稱
private String loginName;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
@Override
public void run() {
// 餓漢式單例
SimpleSingleton simpleSingleton= SimpleSingleton.getInstance();
simpleSingleton.setCount();
System.out.println(getLoginName()+"登入成功:"+simpleSingleton.toString());
}
}
/**
* 單例模式--主程式
*
* @author zhuhuix
* @date 2020-06-01
*/
public class App {
public final static int num = 10;
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
Login login = new Login();
login.setLoginName("" + String.format("%2s", (i + 1)) + "號使用者");
threads[i] = new Thread(login);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
System.out.println("網站共有"+SimpleSingleton.getInstance().getCount()+"個使用者登入");
}
}
輸出如下:
10個執行緒併發登入過程中,獲取到了同一個物件引用地址,即該單例模式是有效的。
1.4.2.2 懶漢模式
- 在初始化時只進行定義。
- 只有在程式中呼叫了該單例類,才會完成例項化( 沒人動我,我才懶得動)。
- 需通過執行緒同步技術才能保證執行緒安全。
我們先看下未使用執行緒同步技術的例子:
/**
* 懶漢式單例模式--未應用執行緒同步技術
*
* @author zhuhuix
* @date 2020-06-01
*/
public class LazySingleton {
// 單例物件
private static LazySingleton APP_INSTANCE;
// 計數器
private AtomicLong count = new AtomicLong(0);
// 單例模式必須保證預設構造方法為私有型別
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (APP_INSTANCE == null) {
APP_INSTANCE = new LazySingleton();
}
return APP_INSTANCE;
}
public AtomicLong getCount() {
return count;
}
public void setCount() {
count.addAndGet(1);
}
}
/**
* 單例模式的應用--登入執行緒
*
* @author zhuhuix
* @date 2020-06-01
*/
public class Login implements Runnable {
....
@Override
public void run() {
// 餓漢式單例
LazySingleton lazySingleton =LazySingleton.getInstance();
lazySingleton.setCount();
System.out.println(getLoginName()+"登入成功:"+lazySingleton);
}
}
/**
* 單例模式--主程式-
*
* @author zhuhuix
* @date 2020-06-01
*/
public class App {
public final static int num = 10;
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
Login login = new Login();
login.setLoginName("" + String.format("%2s", (i + 1)) + "號使用者");
threads[i] = new Thread(login);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
System.out.println("網站共有" + LazySingleton.getInstance().getCount() + "個使用者登入");
}
}
輸出結果:
10個執行緒併發登入過程中,獲取到了四個物件引用地址,該單例模式失效了。
對程式碼進行分析:
// 未使用執行緒同步
public static LazySingleton getInstance() {
// 在多個執行緒併發時,可能會有多個執行緒同時進入 if 語句,導致產生多個例項
if (APP_INSTANCE == null) {
APP_INSTANCE = new LazySingleton();
}
return APP_INSTANCE;
}
我們使用執行緒同步技術對懶漢式模式進行改進:
/**
* 懶漢式單例模式
*
* @author zhuhuix
* @date 2020-06-01
*/
public class LazySingleton {
// 單例物件 ,加入volatile關鍵字進行修飾
private static volatile LazySingleton APP_INSTANCE;
// 計數器
private AtomicLong count = new AtomicLong(0);
// 單例模式必須保證預設構造方法為私有型別
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (APP_INSTANCE == null) {
// 對類進行加鎖,並進行雙重檢查
synchronized (LazySingleton.class) {
if (APP_INSTANCE == null) {
APP_INSTANCE = new LazySingleton();
}
}
}
return APP_INSTANCE;
}
public AtomicLong getCount() {
return count;
}
public void setCount() {
count.addAndGet(1);
}
}
再測試執行:
10個執行緒併發登入過程中,獲取到了同一個物件引用地址,即該單例模式有效了。
1.4.2.3 列舉類實現單例模式
《Effective Java》 推薦使用列舉的方式解決單例模式。這種方式解決了最主要的;執行緒安全、自由序列化、單一例項。
/**
* 利用列舉類實現單例模式
*
* @author zhuhuix
* @date 2020-06-01
*/
public enum EnumSingleton implements Serializable {
// 單例物件
APP_INSTANCE;
// 計數器
private AtomicLong count = new AtomicLong(0);
// 單例模式必須保證預設構造方法為私有型別
private EnumSingleton() {
}
public AtomicLong getCount() {
return count;
}
public void setCount() {
count.addAndGet(1);
}
}
/**
* 單例模式的應用--登入執行緒
*
* @author zhuhuix
* @date 2020-06-01
*/
public class Login implements Runnable {
...
@Override
public void run() {
EnumSingleton enumSingleton = EnumSingleton.APP_INSTANCE;
enumSingleton.setCount();
System.out.println(getLoginName()+"登入成功:"+enumSingleton.toString());
}
}
/**
* 單例模式--主程式
*
* @author zhuhuix
* @date 2020-06-01
*/
public class App {
public final static int num = 10;
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
Login login = new Login();
login.setLoginName("" + String.format("%2s", (i + 1)) + "號使用者");
threads[i] = new Thread(login);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
System.out.println("網站共有"+EnumSingleton.APP_INSTANCE.getCount()+"個使用者登入");
}
}
輸出如下:
10個執行緒併發登入過程中,該單例模式是有效的。
2、單例模式在原始碼中的應用
2.1 JDK原始碼中單例模式
java.lang.Runtime使用了單例模式的餓漢式,原始碼如下:
2.2 Spring原始碼中單例模式
在 Spring 依賴注入Bean例項預設是單例的,我們由此展開。bean 可以被定義為兩種模式:prototype(多例)和 singleton(單例)。
- singleton(單例):只有一個共享的例項存在,所有對這個 bean 的請求都會返回唯一的例項。
- prototype(多例):對這個 bean 的每次請求都會建立一個新的 bean 例項,類似於 new。
例項:配置檔案內容如下:
<bean id="singleton" class="java.util.Date" scope="singleton"></bean>
<bean id="prototype" class="java.util.Date" scope="prototype"></bean>
Spring 中載入單例的過程都是在 BeanFactory 的 getBean() 方法中被定義的,其預設的功能在 AbstractBeanFactory 類中實現,主要包含兩個功能。
- 從快取中獲取單例 Bean。
- Bean 的例項中獲取物件。
getBean() 方法最終會呼叫 AbstractBeanFactory 的 doGetBean() 方法,原始碼如下。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//對傳入的beanName稍作修改,防止有一些非法欄位,然後提取Bean的Name
final String beanName = transformedBeanName(name);
Object bean;
//直接從快取中獲取單例工廠中的objectFactory單例
Object sharedInstance = getsingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" +
beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
}
}
//返回對應的例項,從 Bean例項中獲取物件
bean = getObjectForBeanInstance(sharedInstance,name,beanName, null);
} else {
...
}
...
}
getBean() 方法不僅處理單例物件的邏輯,還處理原型物件的邏輯。繼續看 getSingleton() 方法的程式碼實現。
getSingleton() 的工作流程:singletonObjects-->earlySingletonObjects-->singletonFactories-->建立單例例項
/**
* 單例物件的快取
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先通過名字查詢這個Bean是否存在
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//檢視快取中是否存在這個Bean
singletonObject = this.earlySingletonObjects.get(beanName);
//如果這個時候的Bean例項還為空並且允許懶載入
if (singletonObjects == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
在上面程式碼片段中,synchronized(this.singletonObjects) 是關鍵,但是前提條件 isSingletonCurrentlyInCreation 的返回值也是 true,也就是這個 Bean 正在被建立。因此,第一次呼叫 doGetBean() 的時候,getSingleton() 基本上都是返回 null,所以會繼續執行 doGetBean() 方法中後面的邏輯。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 獲取beanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
...
}
}
可以看到,在 BeanFactory 中,從 XML 中解析出來的相關配置資訊被放在 BeanDefinitionMap 中,通過這個 Map 獲取 RootBeanDefinition,然後執行判斷語句if(mbd.isSingleton())。如果是單例的,則接著呼叫 getSingleton() 的過載方法,傳入 mbd 引數。當從快取中載入單例物件時,會把當前的單例物件在singletonObjects 中存放一份,這樣可以保證在呼叫 getBean() 方法的時候,singletonObjects 中永遠只有一個例項,在獲取物件時才會給它分配記憶體,既保證了記憶體高效利用,又是執行緒安全的。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 直接從快取中獲取單例Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 在singletonObject中新增要載入的單例
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
如此一來,當下次需要這個單例 Bean 時,可以直接從快取中獲取。在 Spring 中建立單例的過程雖然有點繞,但是邏輯非常清楚,就是將需要的物件放在 Map 中,下次需要的時候直接從 Map 中獲取即可。
3、單例模式優缺點與場景
3.1 優點
- 在單例模式中,活動的單例只有一個例項,對單例類的所有例項化得到的都是相同的一個例項。這樣就 防止其它物件對自己的例項化,確保所有的物件都訪問一個例項
- 單例模式具有一定的伸縮性,類自己來控制例項化程式,類就在改變例項化程式上有相應的伸縮性。
- 提供了對唯一例項的受控訪問。
- 由於在系統記憶體中只存在一個物件,因此可以 節約系統資源,當 需要頻繁建立和銷燬的物件時單例模式無疑可以提高系統的效能。
- 允許可變數目的例項。
- 避免對共享資源的多重佔用。
3.2 缺點
- 不適用於變化的物件,如果同一型別的物件總是要在不同的用例場景發生變化,單例就會引起資料的錯誤,不能儲存彼此的狀態。
- 由於單利模式中沒有抽象層,因此單例類的擴充套件有很大的困難。
- 單例類的職責過重,在一定程度上違背了“單一職責原則”。
- 濫用單例將帶來一些負面問題,如為了節省資源將資料庫連線池物件設計為的單例類,可能會導致共享連線池物件的程式過多而出現連線池溢位;如果例項化的物件長時間不被利用,系統會認為是垃圾而被回收,這將導致物件狀態的丟失。
3.3 使用注意事項
- 1.使用時不能用反射模式建立單例,否則會例項化一個新的物件
- 2.使用懶單例模式時注意執行緒安全問題
- 3.餓單例模式和懶單例模式構造方法都是私有的,因而是不能被繼承的,有些單例模式可以被繼承(如登記式模式)
3.4 適用場景
單例模式只允許建立一個物件,因此節省記憶體,加快物件訪問速度,因此物件需要被公用的場合適合使用,如多個模組使用同一個資料來源連線物件等等。如:
- 1.需要頻繁例項化然後銷燬的物件。
- 2.建立物件時耗時過多或者耗資源過多,但又經常用到的物件。
- 3.有狀態的工具類物件。
- 4.頻繁訪問資料庫或檔案的物件。
以下都是單例模式的經典使用場景:
- 1.資源共享的情況下,避免由於資源操作時導致的效能或損耗等。如上述中的日誌檔案,應用配置。
- 2.控制資源的情況下,方便資源之間的互相通訊。如執行緒池等。
3.5 應用場景舉例
- 1.外部資源:每臺計算機有若干個印表機,但只能有一個PrinterSpooler,以避免兩個列印作業同時輸出到印表機。內部資源:大多數軟體都有一個(或多個)屬性檔案存放系統配置,這樣的系統應該有一個物件管理這些屬性檔案
- 2. Windows的Task Manager(工作管理員)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能開啟兩個windows task manager嗎? 不信你自己試試看哦~
- 3. windows的Recycle Bin(回收站)也是典型的單例應用。在整個系統執行過程中,回收站一直維護著僅有的一個例項。
- 4. 網站的計數器,一般也是採用單例模式實現,否則難以同步。
- 5. 應用程式的日誌應用,一般都何用單例模式實現,這一般是由於共享的日誌檔案一直處於開啟狀態,因為只能有一個例項去操作,否則內容不好追加。
- 6. Web應用的配置物件的讀取,一般也應用單例模式,這個是由於配置檔案是共享的資源。
- 7. 資料庫連線池的設計一般也是採用單例模式,因為資料庫連線是一種資料庫資源。資料庫軟體系統中使用資料庫連線池,主要是節省開啟或者關閉資料庫連線所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因為何用單例模式來維護,就可以大大降低這種損耗。
- 8. 多執行緒的執行緒池的設計一般也是採用單例模式,這是由於執行緒池要方便對池中的執行緒進行控制。
- 9. 作業系統的檔案系統,也是大的單例模式實現的具體例子,一個作業系統只能有一個檔案系統。
- 10. HttpApplication 也是單位例的典型應用。熟悉ASP.Net(IIS)的整個請求生命週期的人應該知道HttpApplication也是單例模式,所有的HttpModule都共享一個HttpApplication例項.
4、實現單利模式的原則和過程
- 1.單例模式:確保一個類只有一個例項,自行例項化並向系統提供這個例項
- 2.單例模式分類:餓單例模式(類載入時例項化一個物件給自己的引用),懶單例模式(呼叫取得例項的方法如getInstance時才會例項化物件)(java中餓單例模式效能優於懶單例模式,c++中一般使用懶單例模式)
- 3.單例模式要素:
- a.私有構造方法
- b.私有靜態引用指向自己例項
- c.以自己例項為返回值的公有靜態方法
參考文章:
https://www.cnblogs.com/zhuhuix/p/13030646.html
相關文章
- 2020-12-11——原型模式在JDK以及Spring原始碼中如何進行串聯原型模式JDKSpring原始碼
- 直播原始碼如何進行簡單搭建原始碼
- 設計模式(三)——JDK中的那些單例設計模式JDK單例
- “單例”模式與它在原始碼中的運用單例模式原始碼
- 單例模式的幾種實現與在Android原始碼中的應用單例模式Android原始碼
- Eclipse關聯JDK原始碼EclipseJDK原始碼
- 在Python中實現單例模式Python單例模式
- JavaScript設計模式系列三之單例模式(附案例原始碼)JavaScript設計模式單例原始碼
- 八、目前JDK中,單例模式這3種寫法你知道嗎?JDK單例模式
- 單例模式 – 單例登錄檔與 Spring 實現單例剖析單例模式Spring
- 單例模式 - 單例登錄檔與 Spring 實現單例剖析單例模式Spring
- Spring 原始碼學習 - 單例bean的例項化過程Spring原始碼單例Bean
- 如何檢視JDK以及JAVA框架的原始碼JDKJava框架原始碼
- 在eclipse中關聯android原始碼EclipseAndroid原始碼
- Flutter 中的單例模式Flutter單例模式
- 設計模式(十八)——觀察者模式(JDK Observable原始碼分析)設計模式JDK原始碼
- JDK執行緒池原始碼研究JDK執行緒原始碼
- Android設計模式之——單例模式之原始碼使用場景(一)Android設計模式單例原始碼
- Picasso原始碼分析(一):單例模式、建造者模式、面向介面程式設計原始碼單例模式程式設計
- Zookeeper原始碼分析(三) ----- 單機模式(standalone)執行原始碼模式
- Day68 Spring TX (事務)和配置細節以及單例設計模式Spring單例設計模式
- JS中的單例模式及單例模式原型類的實現JS單例模式原型
- DCL單例模式中的缺陷及單例模式的其他實現單例模式
- JDK(rt.jar)原始碼和IDE關聯JDKJAR原始碼IDE
- Spring中@Transactional事務回滾例項及原始碼Spring原始碼
- 如何看待Spring下單例模式與執行緒安全的矛盾Spring單例模式執行緒
- Python 中的單例模式Python單例模式
- (單例設計模式中)懶漢式與餓漢式在多執行緒中的不同單例設計模式執行緒
- Spring AI 與 Ollama 在本地執行案例原始碼SpringAI原始碼
- 多執行緒設計模式:保護性暫停模式詳解以及其在DUBBO應用原始碼分析執行緒設計模式原始碼
- 在Linux中,如何進行叢集管理?Linux
- java中的單例模式,舉例說明。Java單例模式
- 設計模式之--策略模式及其在JDK中的應用設計模式JDK
- Java 中設計模式 (單例模式) 介紹Java設計模式單例
- 執行緒安全的單例模式執行緒單例模式
- 【設計模式】介面卡模式以及原始碼應用設計模式原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(2)JDK原始碼