考虑下面的struts Action
类,我在execute方法中使用了StringBuilder
变量。我的问题:变量sb
线程是否安全?
public DemoAction extends Action
{
......
public ActionForward execute(.....)
{
StringBuilder sb = new StringBuilder();
}
}
如果在execute()之外声明了相同的变量sb,该怎么办?请记住,WebContainer中只有一个DemoAction对象。?
答案 0 :(得分:14)
局部变量是线程安全的,只要没有其他线程以某种方式获得对同一字符串构建器实例的引用,它是线程安全的。
答案 1 :(得分:3)
它是线程安全的,因为你只在方法的范围内创建和使用它,所以引用将存储在每个线程的本地堆栈空间中
答案 2 :(得分:2)
是的,局部变量本质上是线程安全的。每个线程都有自己的副本。
答案 3 :(得分:1)
来自Java 6 StringBuilder
Javadoc:
此类提供与StringBuffer兼容的API,但不保证同步。此类设计用作StringBuffer的替代品,用于单个线程使用字符串缓冲区的位置(通常情况下)。在可能的情况下,建议首先使用此类优先于StringBuffer,因为在大多数实现中它会更快。
这意味着该类不是线程安全的,您应该更喜欢StringBuffer
,您知道该变量将被同时访问。
但是,在这种情况下,您可以保证仅从一个线程访问您的StringBuilder
,因为它是局部变量而不是实例变量。请参阅问题'Thread safety and local variables'以获得解释。
答案 4 :(得分:0)
来自the spec:
StringBuilder的实例不适合多线程使用。如果需要这样的同步,则建议使用StringBuffer。
但是作为Konrad Rudolph pointed out,在你的情况下,它是一个局部变量,所以你应该没问题
答案 5 :(得分:0)
很安全。此变量是execute()
方法的本地变量,并且每次调用此方法时都会创建,因此在多线程环境中,每个线程都可以拥有自己的sb
变量的单独副本。
答案 6 :(得分:0)
StringBuilder不是线程安全的,但只要您从单个线程使用它,您就不必担心它。即使你从两个线程进行访问,你也可以通过用一个同步块封闭临界区来轻松地使它成为线程安全的,例如
private StringBuilder sb = new StringBuilder();
void appendSomething(String v) {
synchronized (sb) {
sb.append("You entered ");
sb.append(v);
}
}
如果整个方法都是关键部分,你可以说方法
同步synchronized void appendSomething(String v) {
sb.append("You entered ");
sb.append(v);
}
注意我明确写了两个append语句来证明只使用线程安全的StringBuffer不会使代码线程安全。如果你使用StringBuffer运行两个线程,那么每个追加可能会被同步,但仍然可能出现竞争条件。
private StringBuffer sb = new StringBuffer();
void appendSomething(String v) {
sb.append("You entered ");
// Race condition!!!
sb.append(v);
}
因此,两个写“hello”和“world”的线程可能会导致输出“You entered You you into helloworld”,因为每个附加都受到保护而不是整个动作。
使用同步类的效率也较低。例如,在上面的示例中,两个对append的调用都是同步的,因此除了竞争条件之外,我还必须将对象锁定两次,而非同步类一次。