3

我有一个场景,我想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
}

我认为要使这个线程安全,仅仅改变StringBuildertoStringBuffer是不够的。我应该在属性本身上进行同步吗?

4

4 回答 4

8

不是StringBuilder谁有List<String> property危险。你有两个选择:

  1. MakemyMethod和其他改变属性的方法synchronized

  2. 使用java.util.concurrent.CopyOnWriteArrayList线程安全的并为迭代器创建快照

于 2013-06-04T13:22:18.597 回答
4

问题是,当您调用 yoursmyMethod()时,另一个线程可以将 new 添加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();
        }
    }
}
于 2013-06-04T13:30:58.337 回答
3

您可以在property或任何对象上进行同步,只要您在您访问的任何地方对同一property对象进行同步即可。

同步的替代方法是使用 的线程安全实现List,例如CopyOnWriteArrayList,如果经常读取列表但不经常修改,这很好(速度快,争用比同步少)。

于 2013-06-04T13:24:14.817 回答
2

It seems that the synchronize issue lies on property.

So just add a synchronization on it:

synchronized (property) {
   ...
}
于 2013-06-04T13:22:35.533 回答