設計模式中的單例模式的程式碼為什麼解構函式會多次被呼叫,而建構函式只調用一次
單例模式
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!
(解構函式被呼叫)
請按任意鍵繼續. . .