在前一面篇文章[
設計安全的多執行緒應用程式(執行緒安全)
]中,我們講了,什麼是執行緒安全,列舉一些常見的執行緒安全和非執行緒安全的情況。還沒對執行緒安全了解的同學請點上面的鏈結。現在我們來看執行緒不安全的本質是什麼。
我們來想想在單執行緒的情況下安全,為什麼在多執行緒的情況下是不安全的呢?無非就是因為多執行緒是並行執行,當然並行執行本身是沒有錯的。如果這些並行跑起來的執行緒,出現下列情況時可能會導致執行緒不安全。第一,爭搶獨佔的資源如同時寫乙個檔案,對獨佔的資源的排它鎖。第二,程式中的全域性物件,如類中對靜態成員,被多個執行緒同時更新(修改或者刪除),會產生髒的資料或者是其它執行緒得不到正確的資料的後果;同乙個類例項的非靜態成員,被此例項中的函式使用(其中有修改例項成員的功能),此時兩個以上執行緒同時使用時,就可能使類成員的狀態對同乙個執行緒的使用的不一致性。
由此,可以看出,執行緒安全的本質就是,要保護全域性物件,在使用時只能被乙個執行緒使用(包括讀,寫,刪除)(注意,對全域性物件只限於唯讀,那麼是執行緒安全的)。解決的方法無非就是兩種,第一,把這個物件或者資源鎖住,即等我用完了,其它執行緒才能再能,否則其它執行緒等待,這也是最常見的方式。第二,給每個執行緒分配屬於只屬於自己的"全域性物件"(這樣聽起來好像有點彆扭)。
要注意的一點是,很多語句的類庫中的類,都沒在實現執行緒安全,這是因為基於效能的考慮,這樣的情況下,就讓我們程式設計師自己來決定實現執行緒安全。
下面這兩種設計執行緒安全類的例子:
第一,用lock語句(在c#中)
1,鎖住同乙個例項中的全域性資源(同一例項中非靜態成員)
public
void
function()}
2,鎖住類中靜態成員
static
stringbuilder cstrbuild
=new
stringbuilder();
static
system.object lockthis
=new
system.object();
public
void
function()}
第二,使用給每乙個執行緒分配自己的「全域性物件」的方法,實現乙個帶有快取的寫檔案功能的執行緒安全的類(避免每條資料寫一次,造成io瓶頸)。
它的原則是給每個執行緒分配自己的「全域性物件」。
實現功能:
當每個執行緒的stringbuilder物件,到達一定長度 const
intcbufferlenght
=10000*38
; 後才寫入檔案。
步驟是:
1, 宣告乙個分局物件集合,我用了dictionary物件,key是執行緒id,value就是它的「全域性物件」
static
dictionary
<
int, stringbuilder
>
clbufferofethread
=new
dictionary
<
int, stringbuilder
>
();
2,需要注意的是,當第一次將資料加入到全域性集合物件dictionary
時,需要鎖定
dictionary物件
lock
(lockbuffer)
3, 給dictionary物件賦值時,無需使用lock(因為它是執行緒獨佔的全域性物件,不會衝突,我給每個執行緒id分配了自己的「全域性物件」,即集合中的某個元素)
4,在虛構函式處理還未寫入檔案的資料
~streamwritewithbuffer()
valus.remove(
0, valus.length);}}
} 下面就是具體的**,
呼叫**:
streamwritewithbuffer streamwritewithbuffer
=new
streamwritewithbuffer();
//////
writing
content
once a content was created
///
///limpid file name
///public
void
writelimpidlog(
string
pstrcontent)
catch
(exception ex)}
類實現:
using
system;
using
system.collections.generic;
using
system.text;
using
system.io;
using
system.threading;
namespace
project.common
public
streamwritewithbuffer()
~streamwritewithbuffer()
valus.remove(
0, valus.length);}}
}private
static
object lockwrite
=new
object();
private static object lockbuffer = new object();
public
void
writeline(
string
plimpidfilename,
string
pstrcontent)
else
}clbufferofethread[thread.currentthread.managedthreadid].remove(
0, clbufferofethread[thread.currentthread.managedthreadid].length);}}
else}}
catch
(exception ex)
}public
void
dispose()}}
總之,執行緒安全除了在設計時要盡量避免以上的情況之外,還要反覆的測試你的類,或者程式,才能更終實現執行緒安全類。
Redis中字典 Dictionary 的實現
字典 字典,又稱為符號表 symbol table 關聯表 associative array 或對映 map 是一種用於儲存鍵值對 key value pair 的抽象資料結構。在字典裡面,乙個鍵 key 可以和乙個值 value 進行關聯 將鍵對映為值 字典中的每個鍵都是獨一無二的,程式可以在字...
VBA中Dictionary物件使用小結
自 vba中dictionary物件使用小結 dim dict 建立dictionary set dict createobject scripting.dictionary 增加專案 dict.add a 300 dict.add b 400 dict.add c 500 統計專案數 n dict...
在QTP中使用Dictionary物件
vbscript的dictionary 物件與perl的關聯陣列 associative array 類似,其中儲存的內容可以是任何資料,每乙個儲存的資料都與乙個唯一的鍵 key 關聯,鍵用於獲取每一項資料,鍵通常是整型或字串型別。在qtp中,可以把dictionary 當成陣列來用,而且可以隨時新...