国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【設(shè)計模式-單例模式】

這篇具有很好參考價值的文章主要介紹了【設(shè)計模式-單例模式】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

什么是單例模式?

在一個項目中的全局范圍內(nèi), 一個類有且僅有一個實例對象。這個唯一的實例對象給其他模塊提供數(shù)據(jù)的全局訪問。這樣的模式就叫單例模式。
單例模式的典型例子就是任務(wù)隊列。

那么如何去實現(xiàn)這樣的一個單例模式的類?

首先, 考慮單例模式的要求為有且僅有一個實例對象。那么就先從構(gòu)造函數(shù)入手。類的構(gòu)造函數(shù)主要有:構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、賦值運算符重載構(gòu)造函數(shù)。

  • 對于構(gòu)造函數(shù),將構(gòu)造函數(shù)的訪問權(quán)限設(shè)為private , 這樣就禁止了構(gòu)造函數(shù)在類的外部被調(diào)用。而在類的內(nèi)部保證只調(diào)用構(gòu)造函數(shù)一次,這樣就創(chuàng)建了類的唯一對象。又因為單例對象需要提供數(shù)據(jù)的全局訪問,所以將這個唯一對象聲明為 靜態(tài)變量,靜態(tài)變量的生命周期為從創(chuàng)建開始直到程序結(jié)束。一般將靜態(tài)類的唯一對象設(shè)為private(數(shù)據(jù)隱藏,封裝特性),而設(shè)計一個public靜態(tài)函數(shù)提供訪問對象的唯一接口。

關(guān)于類中的靜態(tài)變量和靜態(tài)函數(shù)的一些細節(jié):

  • 類中靜態(tài)變量和靜態(tài)函數(shù)都屬于類,而不屬于任何類的對象。換句話說,一個類只有一個靜態(tài)變量和靜態(tài)函數(shù),多個對象共用這一個。
  • 類的靜態(tài)變量和靜態(tài)函數(shù)在類中都可以直接訪問,但是在類的外部必須在前面加上類名和作用域運算符::;
  • 類的靜態(tài)變量在類的內(nèi)部創(chuàng)建但是在類的外部初始化,一般在類的定義中初始化;而類的靜態(tài)函數(shù)可以在類內(nèi)也可以在類外初始化。 類外初始化別忘記上一點說的加上類名和::
  • 類的靜態(tài)函數(shù)只能訪問靜態(tài)變量和靜態(tài)函數(shù),不能訪問非靜態(tài)變量和非靜態(tài)函數(shù)。所以單例模型類中訪問唯一對象的函數(shù)接口設(shè)為靜態(tài)的。
  • 拷貝構(gòu)造函數(shù)、賦值運算符重載構(gòu)造函數(shù)給禁止掉或設(shè)為私有。這通過=delete 實現(xiàn)。

所以,單例模式的類示例代碼如下:

// 定義一個單例模式的類
class Singleton
{
public:
    // = delete 代表函數(shù)禁用,
    Singleton(const Singleton& obj) = delete;//拷貝構(gòu)造函禁止
    Singleton& operator=(const Singleton& obj) = delete;//賦值構(gòu)造函數(shù)禁止
    static Singleton* getInstance();//靜態(tài)函數(shù)提供訪問唯一實例對象的唯一接口
private:
    Singleton() = default;//構(gòu)造函數(shù)設(shè)為私有,并用default強調(diào)為系統(tǒng)默認的構(gòu)造函數(shù)
    static Singleton* m_obj;//靜態(tài)對象
};

餓漢模式和懶漢模式

根據(jù)實例對象被創(chuàng)建的時機分為餓漢模型懶漢模式。

  • 餓漢模式
// 餓漢模式
class Singleton
{
public:
    // = delete 代表函數(shù)禁用,
    Singleton(const Singleton& obj) = delete;//拷貝構(gòu)造函禁止
    Singleton& operator=(const Singleton& obj) = delete;//賦值構(gòu)造函數(shù)禁止
    static Singleton* getInstance()//靜態(tài)函數(shù)提供訪問唯一實例對象的唯一接口
    {
    	return m_obj;
    }
private:
    Singleton() = default;//構(gòu)造函數(shù)設(shè)為私有
    static Singleton* m_obj;//靜態(tài)對象
};
// 靜態(tài)成員初始化放到類外部處理
Singleton* Singleton::m_obj = new Singleton;

int main()
{
    Singleton* obj = Singleton::getInstance();
}

在餓漢模式下, 在類被加載時對象就被初始化。

  • 懶漢模式
class Singleton
{
public:
    // = delete 代表函數(shù)禁用,
    Singleton(const Singleton& obj) = delete;//拷貝構(gòu)造函禁止
    Singleton& operator=(const Singleton& obj) = delete;//賦值構(gòu)造函數(shù)禁止
    static Singleton* getInstance();//靜態(tài)函數(shù)提供訪問唯一實例對象的唯一接口
    { 
    	if(m_obj == NULL)
    	{
    		m_obj = new Singleton();
    		return m_obj;
    	}
    	else return m_obj;
    }
private:
    Singleton() = default;//構(gòu)造函數(shù)設(shè)為私有
    static Singleton* m_obj;//靜態(tài)對象
};
// 靜態(tài)成員初始化放到類外部處理
Singleton* Singleton::m_obj=NULL;

int main()
{
    Singleton* obj = Singleton::getInstance();
}

懶漢模式下, 單例模式的對象在類加載不去創(chuàng)建,在被使用時才被創(chuàng)建。 所以懶漢模式是更省內(nèi)存的。

線程安全問題

餓漢模式是沒有線程安全問題的, 因為對象在類加載時就被創(chuàng)建出來。多個線程不能再創(chuàng)建新的對象,只能通過類提供的唯一接口訪問對象。
懶漢模式會存在安全問題, 因為對象在使用時被創(chuàng)建。若多個線程同時使用的話可能就會創(chuàng)建多個對象。比如A線程第一次使用對象,使用if(m_obj == NULL)通過,下一步就是創(chuàng)建對象。而恰好此時時間片被線程B給占去,因為對象還為被創(chuàng)建,所以線程B也將開始創(chuàng)建對象,以此類推,所以這就可能創(chuàng)建多個對象,這就違背的單例模型的原則。
解決線程間數(shù)據(jù)同步的問題,最常用的辦法是互斥鎖。當(dāng)一個線程將互斥鎖鎖上的時候,其他線程不能再次上鎖,只能等該線程解鎖后才能進行上鎖和解鎖的操作。換句話說, 同時只能有一個線程持有互斥鎖。(一個坑位只能同時蹲一個人的意思 : )

  • 互斥鎖
class Singleton//互斥鎖的解決方法
{
public:
    // = delete 代表函數(shù)禁用,
    Singleton(const Singleton& obj) = delete;//拷貝構(gòu)造函禁止
    Singleton& operator=(const Singleton& obj) = delete;//賦值構(gòu)造函數(shù)禁止
    static Singleton* getInstance();//靜態(tài)函數(shù)提供訪問唯一實例對象的唯一接口
    { 
   		m_mutex.lock();//鎖上,其他線程給我等著
    	if(m_obj == NULL)//互斥鎖內(nèi)的區(qū)域叫做臨界區(qū),該區(qū)域為原子操作,不能操作系統(tǒng)分段執(zhí)行。
    	{
    		m_obj = new Singleton();
    		return m_obj;
    	}
    	else return m_obj;
    	m_mutex.unlock();//解鎖,其他線程開始搶鎖
    }
private:
    Singleton() = default;//構(gòu)造函數(shù)設(shè)為私有
    static Singleton* m_obj;//靜態(tài)對象
};
// 靜態(tài)成員初始化放到類外部處理
Singleton* Singleton::m_obj=NULL;

int main()
{
    Singleton* obj = Singleton::getInstance();
}

由于互斥鎖的存在,所以多線程的并發(fā)性會在臨界區(qū)被狠狠的限制?。ㄒ淮沃荒苡幸粋€線程操作,其他線程被阻塞),這大大降低了代碼執(zhí)行的效率。

  • 靜態(tài)局部對象

互斥鎖解決了線程安全的問題,但減低了代碼執(zhí)行的效率。但其實還有更好的方法可以解決線程安全的問題,那就是靜態(tài)局部變量。

class Singleton
{
public:
    // = delete 代表函數(shù)禁用,
    Singleton(const Singleton& obj) = delete;//拷貝構(gòu)造函禁止
    Singleton& operator=(const Singleton& obj) = delete;//賦值構(gòu)造函數(shù)禁止
    static Singleton* getInstance();//靜態(tài)函數(shù)提供訪問唯一實例對象的唯一接口
    { 
    	static Singleton m_obj;
        return &m_obj;
    }
private:
    Singleton() = default;//構(gòu)造函數(shù)設(shè)為私有
    static Singleton* m_obj;//靜態(tài)對象
};
// 靜態(tài)成員初始化放到類外部處理
Singleton* Singleton::m_obj=NULL;

int main()
{
    Singleton* obj = Singleton::getInstance();
}

這定義了一個靜態(tài)的局部單例對象,并且將這個對象作為了唯一的單例實例。使用這種方式之所以是線程安全的,是因為在 C++11 標準中有如下規(guī)定,并且這個操作是在編譯時由編譯器保證的:(站在巨人的肩膀上就是舒服)
如果指令邏輯進入一個未被初始化的聲明變量,所有并發(fā)執(zhí)行應(yīng)當(dāng)?shù)却撟兞客瓿沙跏蓟?/code>

總結(jié):

懶漢模式的缺點是在創(chuàng)建實例對象的時候有安全問題(可以用互斥鎖或靜態(tài)局部變量解決),但這樣可以減少內(nèi)存的浪費(如果用不到就不去申請內(nèi)存了)。
餓漢模式則相反,在我們不需要這個實例對象的時候,它已經(jīng)被創(chuàng)建出來,占用了一塊內(nèi)存,但它不會存在線程安全問題。

最后用單例模式實現(xiàn)一個任務(wù)隊列

#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
using namespace std;

class TaskQueue
{
public:
    // = delete 代表函數(shù)禁用, 也可以將其訪問權(quán)限設(shè)置為私有
    TaskQueue(const TaskQueue& obj) = delete;
    TaskQueue& operator=(const TaskQueue& obj) = delete;
    static TaskQueue* getInstance()//獲取任務(wù)隊列單例的唯一接口
    {
        return &m_obj;
    }
    // 任務(wù)隊列是否為空
    bool isEmpty()
    {
        lock_guard<mutex> locker(m_mutex);//c++11特性,相當(dāng)于互斥鎖的上鎖和解鎖
        bool flag = m_taskQ.empty();
        return flag;
    }
    // 添加任務(wù)
    void addTask(int data)
    {
        lock_guard<mutex> locker(m_mutex);
        m_taskQ.push(data);
    }
    // 取出一個任務(wù)
    int takeTask()
    {
        lock_guard<mutex> locker(m_mutex);
        if (!m_taskQ.empty())
        {
            int res = m_taskQ.front();
            m_taskQ.pop();
            return res;
        }
        return -1;
    }
    // 刪除一個任務(wù)
    bool popTask()
    {
        lock_guard<mutex> locker(m_mutex);
        if (!m_taskQ.empty())
        {
            m_taskQ.pop();
            return true;
        }
        return false;
    }
private:
    TaskQueue() = default;
    static TaskQueue m_obj;//餓漢模式下的單例模式,類加載時就被創(chuàng)建,直到程序退出才清理
    queue<int> m_taskQ;//維護的任務(wù)隊列
    mutex m_mutex;
};
TaskQueue TaskQueue::m_obj;

int main()
{
    thread t1([]() {//線程1不斷地往任務(wù)隊列尾部添加任務(wù)
        TaskQueue* taskQ = TaskQueue::getInstance();//獲取類的唯一對象,該對象調(diào)用類通過的接口操作任務(wù)隊列。
        for (int i = 0; i < 100; ++i)
        {
            taskQ->addTask(i + 100);
            cout << "+++push task: " << i+100 << ", threadID: " << this_thread::get_id() << endl;
            this_thread::sleep_for(chrono::milliseconds(500));
        }
    });
    thread t2([]() {//線程2不斷從任務(wù)隊列頭部取出任務(wù)
        TaskQueue* taskQ = TaskQueue::getInstance();
        this_thread::sleep_for(chrono::milliseconds(100));//睡眠100ms,原子操作,不會被打斷
        while (!taskQ->isEmpty())
        {
            int data = taskQ->takeTask();
            cout << "---take task: " << data << ", threadID: " 
                << this_thread::get_id() << endl;
            this_thread::sleep_for(chrono::seconds(1));
        }
    });
    t1.join();//線程1結(jié)束前阻塞在這,等線程結(jié)束后釋放線程1的資源
    t2.join();
}

【設(shè)計模式-單例模式】,設(shè)計模式,設(shè)計模式,單例模式,c++文章來源地址http://www.zghlxwxcb.cn/news/detail-549293.html

//懶漢模式
#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
using namespace std;

class TaskQueue
{
public:
    // = delete 代表函數(shù)禁用, 也可以將其訪問權(quán)限設(shè)置為私有
    TaskQueue(const TaskQueue& obj) = delete;
    TaskQueue& operator=(const TaskQueue& obj) = delete;
    static TaskQueue& getInstance()
    {
        static TaskQueue m_obj;
        return m_obj;
    }
    // 任務(wù)隊列是否為空
    bool isEmpty()
    {
        lock_guard<mutex> locker(m_mutex);//c++11特性,相當(dāng)于互斥鎖的上鎖和解鎖
        bool flag = m_taskQ.empty();
        return flag;
    }
    // 添加任務(wù)
    void addTask(int data)
    {
        lock_guard<mutex> locker(m_mutex);
        m_taskQ.push(data);
    }
    // 取出一個任務(wù)
    int takeTask()
    {
        lock_guard<mutex> locker(m_mutex);
        if (!m_taskQ.empty())
        {
            int res = m_taskQ.front();
            m_taskQ.pop();
            return res;
        }
        return -1;
    }
    // 刪除一個任務(wù)
    bool popTask()
    {
        lock_guard<mutex> locker(m_mutex);
        if (!m_taskQ.empty())
        {
            m_taskQ.pop();
            return true;
        }
        return false;
    }
private:
    TaskQueue() = default;
    //static TaskQueue m_obj;//餓漢模式
    queue<int> m_taskQ;
    mutex m_mutex;
};
//TaskQueue TaskQueue::m_obj;

int main()
{
    thread t1([]() {//線程1
        TaskQueue& taskQ = TaskQueue::getInstance();//獲取單例任務(wù)隊列
        for (int i = 0; i < 100; ++i)
        {
            taskQ.addTask(i + 100);
            cout << "+++push task: " << i+100 << ", threadID: " << this_thread::get_id() << endl;
            this_thread::sleep_for(chrono::milliseconds(500));
        }
    });
    thread t2([]() {//線程2
        TaskQueue& taskQ = TaskQueue::getInstance();
        this_thread::sleep_for(chrono::milliseconds(100));//睡眠100ms,原子操作,不會被打斷
        while (!taskQ.isEmpty())
        {
            int data = taskQ.takeTask();
            cout << "---take task: " << data << ", threadID: " 
                << this_thread::get_id() << endl;
            this_thread::sleep_for(chrono::seconds(1));
        }
    });
    t1.join();//線程1結(jié)束前阻塞在這,等線程結(jié)束后釋放線程1的資源
    t2.join();
}

到了這里,關(guān)于【設(shè)計模式-單例模式】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 設(shè)計模式 ~ 單例模式

    單例模式:指在確保一個類只有一個實例,創(chuàng)建之后緩存以便繼續(xù)使用,并提供一個全局訪問點來訪問該實例; 前端對于單例模式不常用,但對于單例的思想無處不在; 如:彈窗、遮罩層、登錄框、vuex redux 中的 store; 閉包: 模塊化:

    2024年02月16日
    瀏覽(38)
  • 設(shè)計模式-單例模式

    ? ? ? 單例模式(Singleton Pattern)是設(shè)計模式中最簡單且最常用的一種創(chuàng)建型模式,其目的是保證一個類在整個系統(tǒng)中只存在一個實例,并提供全局訪問點來獲取這個唯一實例。這種模式主要適用于那些需要頻繁實例化然后又希望避免因為多次實例化而消耗過多資源或產(chǎn)生副

    2024年01月17日
    瀏覽(25)
  • 設(shè)計模式——單例模式

    設(shè)計模式——單例模式

    確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。 即保證一個類只有一個實例,并且提供一個全局訪問點 優(yōu)點 單例對象在內(nèi)存中只有一個實例,減少了內(nèi)存的開支。尤其對于一個頻繁創(chuàng)建、銷毀的對象時,單例模式的優(yōu)勢就更明顯。 減少系統(tǒng)的性能

    2024年02月16日
    瀏覽(34)
  • 【設(shè)計模式-單例模式】

    【設(shè)計模式-單例模式】

    在一個項目中的全局范圍內(nèi), 一個類 有且僅有一個實例對象 。這個唯一的實例對象給其他模塊提供數(shù)據(jù)的 全局訪問 。這樣的模式就叫 單例模式 。 單例模式的典型例子就是任務(wù)隊列。 首先, 考慮單例模式的要求為有且僅有一個實例對象。那么就先從構(gòu)造函數(shù)入手。類的構(gòu)

    2024年02月13日
    瀏覽(30)
  • 設(shè)計模式(單例模式)

    ????????保證指定的類只有一個實例,不能創(chuàng)建出其他的實例 ? ? ? ? ? ? ? ? 1.1 代碼展示 ? ? ? ? ? ? ? ? 1.2 Singleton類中instance對象的創(chuàng)建時機 ????????????????Singleton類中instance對象的創(chuàng)建時機:在Singleton類被jvm加載的時候創(chuàng)建,Singleton類會在第一次使用的時

    2024年02月15日
    瀏覽(31)
  • 設(shè)計模式一:單例模式

    1、單例模式的實現(xiàn)方式 2、spring中的單例實現(xiàn)方式 spring中的單例不是線程安全的,當(dāng)涉及到共享數(shù)據(jù)時需要記性多線程安全性的處理

    2024年02月20日
    瀏覽(19)
  • 設(shè)計模式_單例模式

    保證該類只有一個實例( static私有變量 ),并提供一個訪問的它的全部訪問點( getInstance() 方法 ),該單例可以被所有程序模塊共享. 1)此類不可被復(fù)制. 2)此類不可被公開構(gòu)造. 也就是說,在c++中,它的 構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),賦值函數(shù) 不能被公開調(diào)用. 個人理解,“懶漢式”,那一定很

    2024年02月12日
    瀏覽(28)
  • 設(shè)計模式一(單例模式)

    主要思路:將構(gòu)造方法私有化,并對外提供一個static的方法來創(chuàng)建對象 缺點:一開始就創(chuàng)建對象,占用系統(tǒng)資源 單線程下不會出現(xiàn)問題,但多線程會會有并發(fā)問題,main方法的測試結(jié)果: 會發(fā)生同一時間創(chuàng)建了多個對象,所以出現(xiàn)了DCL雙重檢索 可以實現(xiàn)延遲實例化,并且是

    2024年01月23日
    瀏覽(24)
  • 設(shè)計模式 : 單例模式筆記

    設(shè)計模式 : 單例模式筆記

    一個類 只能創(chuàng)建一個對象 ,這樣的類的設(shè)計模式就稱為單例模式,該模式保證 系統(tǒng)中 該類 只能有一個實例 (并且 父子進程共享 ),一個很典型的單例類就是C++STL的內(nèi)存池 C++單例模式的基本設(shè)計思路: 私有化 構(gòu)造函數(shù) ,刪除默認的 拷貝構(gòu)造函數(shù) 和 賦值運算符重載 防止對象被直

    2024年02月12日
    瀏覽(28)
  • 設(shè)計模式篇---單例模式

    設(shè)計模式篇---單例模式

    單例模式是結(jié)構(gòu)最簡單的設(shè)計模式,通過單例模式可以保證在整個系統(tǒng)中的一個類只有一個實例,從而節(jié)約系統(tǒng)資源。舉個例子,比如windows電腦下的任務(wù)管理器只能打開一個,這個就是單例模式,如果不這樣做,則會彈出多個窗口,但這些窗口顯示的內(nèi)容完全一樣,浪費了資

    2024年02月10日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包