Java: StringBuilder, static method and possible synchronization problems
Is it possible that such code is not thread safe? This is a static method and we are using a local stringbuilder instance. I suppose the input strings can be held by other objects?
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();
}
source to share
It is not completely thread safe because another thread can modify the same array that was passed in the argument for the parameter strings
. It's not entirely obvious due to the use of varargs, but efficiently (from a thread-safety perspective) the method signature is fair:
public static String cat(String[] strings)
It won't throw any exceptions, but you might not see the last values ββin the array.
As another alternative, you might see something unexpected if it sees a change. For example, suppose we are passing only a single-valued array where the value is first "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();
}
In other words, while you probably expect to see βxβ or βin the result, you might seeβ null. βTo fix this, you can only read each value from the array once:
final StringBuilder sb = new StringBuilder(totLength);
for (int i = 0; i < size; i++) {
String value = strings[i];
if (value != null) {
sb.append(value);
}
}
You can still see an array that changes halfway through (for example, if one thread changes from {"x", "y"}
to {"a", "b"}
, you can see "xb" as the result), but you don't get a false zero.
source to share
This should be Thread Safe, since the strings being passed are immutable. and assuming you are creating totLength
inside a method, everything else is local.
EDIT:
as Jon Skeet points out , it's possible that the vargs value could be passed not only as a sequence of strings (as my answer suggests), but also as a String[]
. In the latter case, there is a possibility that the array will be modified by another thread during processing.
source to share
See Jon Skeet's answer for the array portion.
As for StringBuilder
, it should be safe. Since it StringBuilder
is created inside a method, each call has its own StringBuilder
.
StringBuilder
itself is not synchronized, so if it existed before the static method was called, you'd be better off using StringBuffer
this instead.
source to share