我有一个场景,我想在方法中使用StringBuilder
作为局部变量。我理解如果StringBuilder
是本地方法变量,它应该没有任何关于线程安全的问题。
但是,如果我追加StringBuilder
一个实例变量,如:
class MyClass {
private List<String> property;
public void myMethod() {
StringBuilder sb = new StringBuilder();
for(String s : property) {
sb.append(s);
}
}
// some other methods that mutate property
}
我认为要使此线程安全,只需将StringBuilder
更改为StringBuffer
是不够的。我应该在属性本身同步吗?
答案 0 :(得分:8)
不是StringBuilder
而是List<String> property
处于危险之中。您有两种选择:
使myMethod
和其他方法改变属性synchronized
使用线程安全的java.util.concurrent.CopyOnWriteArrayList
并为迭代器创建快照
答案 1 :(得分:4)
问题在于,当您呼叫您的myMethod()
时,另一个线程可能会将新的String
添加到您的property
列表中,从而修改结果。
避免这种情况的一种方法是在以任何方式访问属性的方法中使用synchronized
,或者您可以使用旧的ReadWriteLock
。最常用的实现是ReentrantReadWriteLock
。互联网上有很好的例子,但你会做的是:
class MyClass {
private final ReadWriteLock propertiesLock = new ReentrantReadWriteLock();
private final Lock read = propertiesLock.readLock();
private final Lock write = propertiesLock.writeLock();
...
public StringBuilder myMethod() {
StringBuilder builder = new StringBuilder();
read.lock();
try {
// your writing here.
} finally {
read.unlock();
}
return builder;
}
public void addProperty(String property) {
write.lock();
try {
properties.add(property);
} finally {
write.unlock();
}
}
}
答案 2 :(得分:3)
您可以在property
或任何对象上进行同步,只要您在访问property
的任何位置同步相同的对象。
同步的替代方法是使用List
的线程安全实现,例如CopyOnWriteArrayList
,如果列表经常被读取,那么它很好(快速,争用少于同步)经常修改。
答案 3 :(得分:2)
似乎同步问题在于属性。
所以只需在其上添加同步:
synchronized (property) {
...
}