[英]Java: StringBuilder, static method and possible synchronization issues
像這樣的代碼是否可能不是線程安全的? 它是一個靜態方法,我們使用的是stringbuilder的本地實例。 我猜輸入字符串可能被其他對象保存?
public static String cat(final String ... strings) {
...
...
final StringBuilder sb = new StringBuilder(totLength);
for (int i = 0; i < size; i++) {
if (strings[i] != null) {
sb.append(strings[i]);
}
}
return sb.toString();
}
它不是完全線程安全的 - 因為另一個線程可能正在更改在strings
參數的參數中傳遞的相同數組。 由於您使用了varargs,這並不完全是顯而易見的,但有效地(就線程安全而言)方法簽名只是:
public static String cat(String[] strings)
它不會導致任何異常,但您可能看不到數組中的最新值。
作為另一種選擇,如果它確實看到了變化,您可能會看到意外的事情。 例如,假設我們只傳入一個單值數組,其值最初為“x”:
public static String cat(final String ... strings) {
...
...
final StringBuilder sb = new StringBuilder(totLength);
for (int i = 0; i < size; i++) {
// strings[0] is currently "x"
if (strings[i] != null) {
// But now another thread might change it to null!
// At that point we'd get "null" as output
sb.append(strings[i]);
}
}
return sb.toString();
}
換句話說,雖然您可能希望看到“x”或“”作為結果,但您可以看到“null”。 為了解決這個問題,你可以從陣列讀取每個值只有一次 :
final StringBuilder sb = new StringBuilder(totLength);
for (int i = 0; i < size; i++) {
String value = strings[i];
if (value != null) {
sb.append(value);
}
}
您可能仍然會看到一個數組在更改的一半(例如,如果一個線程正在將{"x", "y"}
更改為{"a", "b"}
您可能會看到“xb”作為結果),但你不會得到虛假的“空”。
這應該是線程安全的,因為傳入的字符串是不可變的。 假設你在方法中創建了totLength
,其他一切都是本地的。
編輯:
正如Jon Skeet指出的那樣 ,vargs值有可能不僅作為一個字符串序列傳遞(如我的答案所假設的那樣),而且還可以傳遞給String[]
。 在后一種情況下,有可能在處理時由另一個線程修改數組。
不,它是寫的(*)線程安全的。 字符串是不可變的,因此多個線程調用它並不重要。
(*代表您顯示的代碼)
即使你沒有傳遞不可變對象,這也是線程安全的,因為
請參閱John Skeet對陣列部分的回答。
至於StringBuilder
,它應該是安全的。 因為StringBuilder
是在方法內創建的,所以每個調用都有自己的StringBuilder
。
StringBuilder
本身不是同步的,所以如果它在靜態方法調用之前存在,那么最好使用StringBuffer
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.