1. 程式人生 > >設計模式中的單例模式的程式碼為什麼解構函式會多次被呼叫,而建構函式只調用一次

設計模式中的單例模式的程式碼為什麼解構函式會多次被呼叫,而建構函式只調用一次

單例模式

package com.seven.exercise.testEception;


/**
 * 單例模式,餓漢式
 * @author Seven
 *
 */
public class SingleDemoHunger {


    private SingleDemoHunger() {


    }


    private static SingleDemoHunger sdh = new SingleDemoHunger();


    public static SingleDemoHunger getInstance() {
        return sdh;
    }


}


package com.seven.exercise.testEception;


/**
 * 懶漢式
 * @author Seven
 *
 */
public class SingleDemo {
    
    /**
     * 私有化建構函式
     */
    private SingleDemo(){
        
    }
    
    private static SingleDemo singleDemo = null;
    
    /**
     * 提供獲取例項的方法
     * @return
     */
    public static SingleDemo getInstance(){
        if(singleDemo==null){
            singleDemo = new SingleDemo();
        }
        return singleDemo;
    } 
}

餓漢式屬於立即載入,所以不存在在多執行緒中出現錯誤的情況;

但是懶漢式的話就有可能出現問題了,如多一個執行緒執行到判斷是否為空的語句

if(singleDemo==null)

的時候,當前執行緒被阻塞,而第二個執行緒進來了,這樣的話第二個執行緒建立了新的物件,那麼第一個執行緒被喚醒的時候又建立多一個物件,這樣在記憶體中就存在了兩個物件,明顯和單例設計模式不符,那麼我們應該怎麼做呢?

很簡單,用 synchronized關鍵字就可以輕鬆解決:

package com.seven.exercise.testEception;


/**
 * 懶漢式
 * @author Seven
 *
 */
public class SingleDemo {
    
    /**
     * 私有化建構函式
     */
    private SingleDemo(){
        
    }
    
    private static SingleDemo singleDemo = null;
    
    /**
     * 提供獲取例項的方法,用synchronized來解決多執行緒的問題.C++ 使用 lock() 和unlock()來實現
     * @return
     */
    public static SingleDemo getInstance(){
        synchronized (SingleDemo.class) {
            if(singleDemo==null){
                singleDemo = new SingleDemo();
            }
        }
        return singleDemo;
    }
    
    
}


這樣就減少了建立多個例項的可能,但是還是存在建立多個例項的可能性,而且同步鎖肯定要消耗資源,這樣的話就會降低效率,那麼有什麼辦法可以提高效率呢?答案是有的,那就是通過二次判斷,這樣的話就不用每次都執行同步程式碼塊,這樣的話,只需第一次執行的時候比較佔資源,以後的話就和之前的一樣了:

package com.seven.exercise.testEception;


/**
 * 懶漢式
 * @author Seven
 *
 */
public class SingleDemo {
    
    /**
     * 私有化建構函式
     */
    private SingleDemo(){
        
    }
    
    private static SingleDemo singleDemo = null;
    
    /**
     * 提供獲取例項的方法,用synchronized來解決多執行緒的問題.
     * @return
     */
    public static SingleDemo getInstance(){
        //二次判斷提高效率
        if(singleDemo==null){
            synchronized (SingleDemo.class) {
                if(singleDemo==null){
                    singleDemo = new SingleDemo();
                }
            }
        }
        return singleDemo;
    }
    
    
}


設計模式中的單例模式的程式碼為什麼解構函式會多次被呼叫,而建構函式只調用一次


********************************************************************
 created: 2006/07/20
 filename:  Singleton.h
 author:  李創
                http://www.cppblog.com/converse/

 purpose: Singleton模式的演示程式碼
*********************************************************************/

#ifndef SINGLETON_H
#define SINGLETON_H

class Singleton
{
public:
 Singleton();
 ~Singleton();

 // 靜態成員函式,提供全域性訪問的介面
 static Singleton* GetInstancePtr();
 static Singleton  GetInstance();

 void Test();

private:
 // 靜態成員變數,提供全域性惟一的一個例項
 static Singleton* m_pStatic;
};

#endif

 

/********************************************************************
 created: 2006/07/20
 filename:  Singleton.cpp
 author:  李創
                http://www.cppblog.com/converse/

 purpose: Singleton模式的演示程式碼
*********************************************************************/

#include "Singleton.h"
#include <iostream>

// 類的靜態成員變數要在類體外進行定義
Singleton* Singleton::m_pStatic = NULL;

Singleton::Singleton()
{
     std::cout << "建構函式被呼叫/n";
}

Singleton::~Singleton()
{
     std::cout << "解構函式被呼叫/n";
}

Singleton* Singleton::GetInstancePtr()
{
 if (NULL == m_pStatic)
 {
  m_pStatic = new Singleton();
 }

 return m_pStatic;
}

Singleton Singleton::GetInstance()
{
 return *GetInstancePtr();
}

void Singleton::Test()
{
 std::cout << "Test函式被呼叫!/n";
}

 

/********************************************************************
 created: 2006/07/20
 filename:  Main.cpp
 author:  李創
                http://www.cppblog.com/converse/

 purpose: Singleton模式的測試程式碼
*********************************************************************/

#include "Singleton.h"
#include <stdlib.h>

 

//解構函式只被呼叫一次的情形:

int main()
{
 // 不用初始化類物件就可以訪問了
 for( int i =0; i < 10; i++)

{

     Singleton::GetInstancePtr()->Test();//程式執行完這一句之後解構函式被呼叫一次,如果是第一次,建構函式被呼叫

   //並且建構函式只被呼叫一次

 

}

 return 0;
}

 

 

程式執行結果:

建構函式被呼叫
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!
Test函式被呼叫!

 

解構函式多次被呼叫的情況:

void Test();

int g_iTest = 0;

int main()
{

 for( int i = 0; i < 5; i++ )//解構函式5次被呼叫
 {
  Test();
 }

 system("pause");

 return 0;
}

void Test()
{
 g_iTest++;
 printf( "第 %d 次呼叫成員函式", g_iTest );
 Singleton::GetInstance().Test();
 
 printf( "/n/n" );
}

第 1 次呼叫成員函式(建構函式被呼叫)Test!
(解構函式被呼叫)

第 2 次呼叫成員函式Test!
(解構函式被呼叫)

第 3 次呼叫成員函式Test!
(解構函式被呼叫)

第 4 次呼叫成員函式Test!
(解構函式被呼叫)

第 5 次呼叫成員函式Test!
(解構函式被呼叫)

請按任意鍵繼續. . .