String 物件一旦在記憶體被配置之後,他就不能夠再改變了,所以他常常被說成是 immutable object。但我們卻很習慣寫成這樣:
三行程式寫完後,請求了三塊新的記憶體配置,也同時浪費了兩塊記憶體。
針對這個問題,Java 提供了 StringBuffer 物件,讓我們可以對字串加加減減,也不會另外再要一塊新的記憶體位址來存放。在這物件當中,Java 還考慮到多執行緒的問題,也就是說,不同的執行緒不會同時對同一個 StringBuffer 物件做新增或是修改的動作,例如當執行緒 A 在使用 「StringBuffer 甲」的時候,執行緒 B 必須等到執行緒 A 完成「StringBuffer 甲」的處理動作 之後才能使用,這就是我們常說的 thread-safe。
對於 Java 所提供的 StringBuffer 物件,針對字串串接的執行校能上,的確可以非常明顯地看到提昇,但一般對程式設計師來說,大部分時機其實可能都不需要考量多執行緒的問題,如果不考慮多執行緒的情況下,減少多餘的判斷處理,是否還有機會再提昇字串串接的效能呢?
果真,在 JDK 1.5. 之後,開始出現了新的物件 StringBuilder ,他與 StringBuffer 的用途幾乎如出一轍,唯一的不同是減少了多執行緒的考量。日後如果只是在寫單一執行緒的程式考量下,StringBuilder 會是較好的選擇。「StringBuffer vs. StringBuilder performance comparison」文章作者Daniel 針對 StringBuilder 與 StringBuffer 兩者間的效能寫了一段簡單的程式來比較,而我自己也透過他的程式在自己電腦上得到了下面數據:
從數據上看來, StringBuilder 已經比 StringBuffer 提昇了一倍以上的效能,當然這兩者更遠遠超過 String 的字串串接。
同樣的情況,也出現在 微軟的 C# 裡。在字串串接的情況下, StringBuilder 遠比 String 的效能提昇很多,唯一讓我不解的,是這次微軟的身上少了 StringBuffer 的味道...,我很認真的想知道這次微軟為何沒收錄 StringBuffer 這物件,但迄今依舊無解。而微軟的 StringBuilder,同樣也是不考慮多執行緒,可以在微軟的官方文件「StringBuilder Class」看到 Thread Safety 的聲明:
Any public static (Shared in Visual Basic) members of this type are thread safe.
Any instance members are not guaranteed to be thread safe.
Any instance members are not guaranteed to be thread safe.
可從上面申明中知道,C# 裡面的 StringBuilder 並不是 thread-safe。
另一個有趣的地方,是從 JDK 釋出的時程來看看,彷彿 .net 在 2003年時釋出的 .net 1.1, 已經比 Java 更早公佈 StringBuilder 物件了!
經由這一次的整理,可以知道 String 在字串串接上所面臨的效能瓶頸,並透過 Daniel 的程式在定量上可以得到支撐。此外,也可以更清楚去分別依據是否為單一執行緒來正確抉擇 StringBuilder 或 StringBuffer。
參考:
01:StringBuffer vs. StringBuilder performance comparison
02:StringBuilder Class
03:Java JDK (Java Development Kit) Releases Dates and Release Differences
04:Java SE 6全方位學習
05:StringBuilder和StringBuffer的差別及清空內容方式
06:StringBuilder vs StringBuffer
07:Why use StringBuilder? StringBuffer can work with multiple thread as well as one thread?
08:StringBuffer and StringBuilder
09:Is the C# '??' operator thread safe?
10:如何:增進 Visual C# .NET 中的字串串連效能
11:Daniel 簡單測試程式
沒有留言:
張貼留言