我读过一些关于String和StringBuilder在Java编程语言中的优缺点的文章。在其中一篇文章中,提交人提到:
StringBuilder不是线程安全的,所以在多线程中使用StringBuffer.
不幸的是,我无法理解这意味着什么。请您解释一下String、StringBuilder和StringBuffer之间的区别,特别是在“线程安全”的上下文中。
如果您能用代码示例进行描述,我将不胜感激。
发布于 2014-11-11 08:01:29
如果多个线程正在修改同一个StringBuilder实例,结果可能是意外的--即一些修改可能会丢失。这就是为什么在这种情况下应该使用StringBuffer的原因。但是,如果每个线程StringBuilder实例只能由一个线程修改,那么最好使用StringBuilder,因为它会更高效(线程安全性带来性能成本)。
发布于 2014-11-11 08:07:52
如果多个线程试图更改StringBuilder对象值,则结果将是奇怪的。参见下面的示例,
private StringBuilder sb = new StringBuilder("1=2");
public void addProperty(String name, String value) {
if (value != null && value.length() > 0) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(name).append('=').append(value);
}
}如果许多线程调用addProperty方法,那么结果将是奇怪的(不可预测的结果)。
Thread1: addProperty("a", "b");
Thread2: addProperty("c", "d");
Thread3: addProperty("e", "f");最后,当您调用sb.toString()时,结果将是不可预测的。例如,它可能带来类似于1=2,ac=d=b,e=f的输出,但您的期望是1=2,a=b,c=d,e=f
发布于 2014-11-11 10:36:41
StringBuilder的线程安全问题是对StringBuilder的方法调用不同步。
考虑一下StringBuilder.append(char)方法的实现:
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
// from the superclass
public AbstractStringBuilder append(char c) {
int newCount = count + 1;
if (newCount > value.length)
expandCapacity(newCount);
value[count++] = c;
return this;
}现在假设您有两个线程共享一个StringBuilder实例,并且都试图同时追加一个字符。假设它们同时到达value[count++] = c;语句,而count是1。每个字符都将写入value[1]的缓冲区中,然后更新count。很明显只有一个字符可以存储在那里..。所以另一只就会迷路。此外,count的增量之一可能会丢失。
更糟糕的是,即使两个线程没有同时到达那里,value[count++] = c;语句也可能失败。原因是Java内存模型说,除非有适当的同步(或者更准确地说,在关系之前发生),否则不能保证第二个线程会看到第一个线程所做的内存更新。实际情况取决于是否和何时将第一个线程的更新写入主内存。
现在让我们来看看StringBuffer.append(char)
public synchronized StringBuffer append(char c) {
super.append(c); // calls the "AbstractStringBuilder.append" method above.
return this;
}这里我们看到append方法是synchronized。这意味着两件事:
append对象上执行超类StringBuffer方法。因此,第一种情况不可能发生。synchronize意味着在不同线程对StringBuffer.append进行的连续调用之间发生了一个事件。这意味着保证后面的线程能够看到在前面的线程中所做的更新。String的情况又不同了。如果我们检查代码,我们将看到没有公开的同步。但这是可以的,因为String对象实际上是不可变的;也就是说,在String API中没有方法会导致String对象的状态发生外部可观察的变化。此外:
final实例变量和构造函数的特殊行为意味着所有线程都将看到任何String的正确初始状态。String是可变的地方,无论线程是否看到对hash变量的最新更改,hashCode()方法都将正确工作。参考文献:
https://stackoverflow.com/questions/26860173
复制相似问题