程式設計師面試時,線程安全知識點經常會遇到。
小洪是一名java程式設計師,工作兩年多了,最近去了某網際網路公司面試,面試時,面試官問了這樣一個問題:
面試官:StringBuilder和StringBuffer有什麼區別?
小洪:StringBuilder線程不安全的,StringBuffer是線程安全的
面試官:能舉個例子說說StringBuilder是怎麼線程不安全的嗎?
小洪:……
小洪有點懵了,平時在用在使用StringBuilder追加字符時,只是簡單的用,只知道它是不是線程安全,至於不安全在哪裡,小洪並沒有去關注。
見小洪沒有作答,面談時面試官又問,StringBuffer哪裡安全了,小洪也回答不出個所以然。
面試官:你都工作兩年了,這個都不知道,怎麼寫出穩定的程序啊?小洪一臉的無助,不過確實不應該,類似StringBuilder常見的知識點,平時應該不會少用,應該掌握才對。
剛畢業的時候,面試時也遇到了類似關於StringBuild的問題,關於StringBuild線程不安全簡單來說StringBuilder沒有加鎖,而StringBuffer有加鎖。面試時,這樣回答固然沒有錯,但要是能進一步分析個所以然那就更好了,相信能給面試官留下更好的印象。
我們舉個例子來驗證下
1. 分別用500個線程寫StringBuffer和StringBuilder,
2. 保證在各自500個線程執行完後列印StringBuffer和StringBuilder字符串長度
3. 檢驗運行結果。
測試
我們創建了500個線程,每個線程往StringBuilder對象裡面append一個字符p。正常情況下代碼應該輸出500,但是實際運行結果是什麼呢?
測試結果
我們看到字符串長度有時候是496,有時候是498,小於預期值500。而當我們把StringBuilder換成StringBuffer不管運行多少次,結果的值都是500,從這個例子我們可以得出StringBuffer線程安全,StringBuilder線程不安全得到了證明。
為什麼輸出值跟預期值不一樣,源碼分析
為什麼會小於期望值,我們來看下StringBuilder的源碼
StringBuilder的append()方法調用的父類AbstractStringBuilder的append()方法,我們來看下這個方法具體做了什麼。
細心的你會發現count += len;這一行代碼並不是一個原子操作。
假設count的值為10,len值為1,這時候有兩個線程同時執行到了這行代碼,count值都是10,執行完後將結果賦值給count,這兩個線程執行完後count值為11,而不是12。這就是為什麼測試代碼輸出的值要小於我們的期望值500的原因了。
而當我們換成StringBuffer類是,為什麼能保證輸出的是500,我們看一下StringBuffer源碼就會發現所有寫操作都有synchronized修飾了
而StringBuilder的寫操作則沒有使用synchronized進行修飾。
StringBuilder類的append方法
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
StringBuffer 類的append方法
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
關於StringBuilder不是線程安全的例子就分析到這。筆者覺得類似這樣的基礎知識點需要在平時學習中不斷摸索,不斷去探索實踐,不斷運用,才能在工作中更好地解決問題。由於筆者水平有限,文中紕漏之處在所難免,權當拋磚引玉,不妥之處,敬請讀者不吝賜教,是為至盼。
來源:https://www.toutiao.com/i6761277756698264071/
喜歡對你有幫助的話記得加個關注不迷路哦
還有關注我私信回復【資料】可以領取到一些個人收集的面試及電子書資料,或許對你有幫助!