Java:使用StringBuilder进行线程安全

时间:2013-06-04 13:17:57

标签: java multithreading thread-safety stringbuilder

我有一个场景,我想在方法中使用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是不够的。我应该在属性本身同步吗?

4 个答案:

答案 0 :(得分:8)

不是StringBuilder而是List<String> property处于危险之中。您有两种选择:

  1. 使myMethod和其他方法改变属性synchronized

  2. 使用线程安全的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) {
   ...
}