像这样的代码是否可能不是线程安全的?它是一个静态方法,我们使用的是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();
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 11
它不是完全线程安全的 - 因为另一个线程可能正在更改strings参数参数中传递的相同数组.由于您使用了varargs,这并不完全是显而易见的,但有效地(就线程安全而言)方法签名只是:
public static String cat(String[] strings)
Run Code Online (Sandbox Code Playgroud)
它不会导致任何异常,但您可能看不到数组中的最新值.
作为另一种选择,如果它确实看到了变化,您可能会看到意外的事情.例如,假设我们只传入一个单值数组,其值最初为"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();
}
Run Code Online (Sandbox Code Playgroud)
换句话说,虽然您可能希望看到"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);
}
}
Run Code Online (Sandbox Code Playgroud)
您可能仍然会看到一个数组在更改的一半(例如,如果一个线程正在改变{"x", "y"},{"a", "b"}您可能会看到"xb"作为结果),但您不会得到虚假的"null".
这应该是线程安全的,因为传入的字符串是不可变的.假设你totLength在方法中创建,其他一切都是本地的.
编辑:
正如Jon Skeet指出的那样,vargs值有可能不仅作为一系列字符串传递(如我的答案所假设的那样),而且还可以传递给String[].在后一种情况下,有可能在处理时由另一个线程修改数组.