日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 线程 单例_多线程单例模式

發布時間:2023/12/10 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 线程 单例_多线程单例模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

多線程單例模式

原文:https://blog.csdn.net/u011726005/article/details/82356538

1. 餓漢模式

使用餓漢模式實現單例是十分簡單的,并且有效避免了線程安全問題,因為將該單例對象定義為static變量,程序啟動即將其構造完成了。代碼實現:

classSingleton {public:static Singleton*GetInstance() {returnsingleton_;

}static voidDestreyInstance() {if (singleton_ !=NULL) {deletesingleton_;

}

}private://防止外部構造。

Singleton() = default;//防止拷貝和賦值。

Singleton& operator=(const Singleton&) = delete;

Singleton(const Singleton& singleton2) = delete;private:static Singleton*singleton_;

};

Singleton* Singleton::singleton_ = newSingleton;intmain() {

Singleton* s1 =Singleton::GetInstance();

std::cout<< s1 <<:endl>

Singleton* s2 =Singleton::GetInstance();

std::cout<< s2 <<:endl>

Singleton.DestreyInstance();return 0;

}

2.懶漢模式

餓漢方式不論是否需要使用該對象都將其定義出來,可能浪費了內存,或者減慢了程序的啟動速度。所以使用懶漢模式進行優化,懶漢模式即延遲構造對象,在第一次使用該對象的時候才進行new該對象。

而懶漢模式會存在線程安全問題,最出名的解決方案就是Double-Checked Locking Pattern (DCLP)。使用兩次判斷來解決線程安全問題并且提高效率。代碼實現:

#include #include

classSingleton {public:static Singleton*GetInstance() {if (instance_ ==nullptr) {

std::lock_guard<:mutex> lock(mutex_);if (instance_ ==nullptr) {

instance_= newSingleton;

}

}returninstance_;

}~Singleton() = default;//釋放資源。

voidDestroy() {if (instance_ !=nullptr) {deleteinstance_;

instance_=nullptr;

}

}void PrintAddress() const{

std::cout<< this <<:endl>

}private:

Singleton()= default;

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;private:static Singleton*instance_;staticstd::mutex mutex_;

};

Singleton* Singleton::instance_ =nullptr;

std::mutex Singleton::mutex_;intmain() {

Singleton* s1 =Singleton::GetInstance();

s1->PrintAddress();

Singleton* s2 =Singleton::GetInstance();

s2->PrintAddress();return 0;

}

3. 懶漢模式優化

上述代碼有一個問題,當程序使用完該單例,需要手動去調用Destroy()來釋放該單例管理的資源。如果不去手動釋放管理的資源(例如加載的文件句柄等),雖然程序結束會釋放這個單例對象的內存,但是并沒有調用其析構函數去關閉這些管理的資源句柄等。解決辦法就是將該管理的對象用智能指針管理。代碼如下:

#include #include#include

classSingleton {public:static Singleton&GetInstance() {if (!instance_) {

std::lock_guard<:mutex> lock(mutex_);if (!instance_) {

instance_.reset(newSingleton);

}

}return *instance_;

}~Singleton() = default;void PrintAddress() const{

std::cout<< this <<:endl>

}private:

Singleton()= default;

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;private:static std::unique_ptrinstance_;staticstd::mutex mutex_;

};

std::unique_ptrSingleton::instance_;

std::mutex Singleton::mutex_;intmain() {

Singleton& s1 =Singleton::GetInstance();

s1.PrintAddress();

Singleton& s2 =Singleton::GetInstance();

s2.PrintAddress();return 0;

}

4. Double-Checked Locking Pattern存在的問題

Double-Checked Locking Pattern (DCLP)實際上也是存在嚴重的線程安全問題。Scott Meyers and 和Alexandrescu寫的一篇文章里面專門分析了這種解決方案的問題C++ and the Perils of Double-Checked Locking。文章截圖:

比如剛剛實現方式很容易發現其存在線程安全問題。

if (instance_ ==nullptr) { \\ 語句1

std::lock_guard<:mutex> lock(mutex_);if (instance_ ==nullptr) {

instance_= newSingleton; \\ 語句2

}

}

線程安全問題產生的原因是多個線程同時讀或寫同一個變量時,會產生問題。

如上代碼,對于語句2是一個寫操作,我們用mutex來保護instance_這個變量。但是語句1是一個讀操作,if (instance_ == nullptr),這個語句是用來讀取instance_這個變量,而這個讀操作是沒有鎖的。所以在多線程情況下,這種寫法明顯存在線程安全問題。

《C++ and the Perils of Double-Checked Locking》這篇文章中提到:

instance_ = new Singleton;

這條語句實際上做了三件事,第一件事申請一塊內存,第二件事調用構造函數,第三件是將該內存地址賦給instance_。

但是不同的編譯器表現是不一樣的??赡芟葘⒃搩却娴刂焚x給instance_,然后再調用構造函數。這是線程A恰好申請完成內存,并且將內存地址賦給instance_,但是還沒調用構造函數的時候。線程B執行到語句1,判斷instance_此時不為空,則返回該變量,然后調用該對象的函數,但是該對象還沒有進行構造。

5. 使用std::call_once實現單例

在C++11中提供一種方法,使得函數可以線程安全的只調用一次。即使用?std::call_once?和?std::once_flag?。std::call_once是一種lazy load的很簡單易用的機制。實現代碼如下:

#include #include#include

classSingleton {public:static Singleton&GetInstance() {staticstd::once_flag s_flag;

std::call_once(s_flag, [&]() {

instance_.reset(newSingleton);

});return *instance_;

}~Singleton() = default;void PrintAddress() const{

std::cout<< this <<:endl>

}private:

Singleton()= default;

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;private:static std::unique_ptrinstance_;

};

std::unique_ptrSingleton::instance_;intmain() {

Singleton& s1 =Singleton::GetInstance();

s1.PrintAddress();

Singleton& s2 =Singleton::GetInstance();

s2.PrintAddress();return 0;

}

6.使用局部靜態變量實現懶漢

使用C++局部靜態變量也可解決上述問題。

#include

classSingleton {public:static Singleton&GetInstance() {staticSingleton intance;returnintance;

}~Singleton() = default;private:

Singleton()= default;

Singleton(const Singleton&) = delete;

Singleton& operator=(const Singleton&) = delete;

};intmain() {

Singleton& s1 =Singleton::GetInstance();

std::cout<< &s1 <<:endl>

Singleton& s2 =Singleton::GetInstance();

std::cout<< &s2 <<:endl>

}

局部靜態變量可以延遲對象的構造,等到第一次調用時才進行構造。

C++11中靜態變量的初始化時線程安全的。通過調試,在進行局部靜態變量初始化的時候,確實會執行以下代碼來保證線程安全。

=================?End

總結

以上是生活随笔為你收集整理的java 线程 单例_多线程单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。