同步在StringBuilder和StringBuffer类方面意味着什么?

时间:2015-06-24 06:40:02

标签: java multithreading stringbuilder stringbuffer

我对'synchronized'这个术语感到很困惑,我从java文档中得到了以下内容。

  

可变的字符序列。该类提供API   与StringBuffer兼容,但不保证   同步。此类旨在用作插入   在字符串缓冲区所在的位置替换StringBuffer   由单个线程使用(通常是这种情况)。哪里   可能,建议优先使用此类   StringBuffer ,因为在大多数实现中它会更快。

据我所知,同步与线程及其访问方式有关。

让我们说,我有一个在其中一个方法中使用StringBuilder的Web应用程序,

  • 这里不保证同步意味着什么?
  • 我应该担心什么吗?我什么时候应该担心多线程?有什么例子吗?
  • 我应该何时关心保证和无保障 同步?
  • 拥有多个线程的Web应用程序的示例是什么?

一个例子将受到高度赞赏。

请注意我知道多线程访问需要同步,因为他们需要访问相同的数据!我需要有一个例子。

7 个答案:

答案 0 :(得分:3)

如果多个线程可以同时访问同一个StringBuilder实例,则应该关注同步。在这种情况下,您应该考虑使用StringBuffer

例如,您应该考虑使用StringBuffer代替StringBuilder

public class Test implements Runnable
{
    public static StringBuilder sb = new StringBuilder();

    public void run ()
    {
        Test.sb.append ("something");
    }

    public static void main (String[] args)
    {
        // start two threads
        new Thread (new Test()).start();
        new Thread (new Test()).start();
    }
}

如果某个方法的本地StringBuilder实例,则不存在其他线程访问它的风险,因此您不需要同步,使用StringBuilder会更有效。

答案 1 :(得分:1)

synchronized关键字没有显示在生成的JavaDoc中,但是如果打开StringBuffer的源代码,您将看到每个可以更改实例状态的公共方法实际上在其签名中都有synchronized关键字。

例如getChars方法

   /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                      int dstBegin)
    {
        super.getChars(srcBegin, srcEnd, dst, dstBegin);
    }

答案 2 :(得分:1)

想象一下,你有一个变量myElement作为StringBuffer。您的应用程序有来自不同报纸的新闻源,并且您有多个线程从各种来源填充。 线程会在DOM element描述的myElement中找到他们的新信息。一旦找到它,它们就会修改myElement,因此其他线程知道在哪里找到新的新闻。由于同步,一个线程在有权访问同一个变量时会阻塞另一个线程,但在这种情况下不会,所以当一个线程在被修改并且半完成时读取myElement时会发生这种情况。对不存在的DOM的一部分的引用。

答案 3 :(得分:1)

使用StringBuffer几乎没有意义:

  • 大部分时间,您可以使用本地StringBuilder变量,只涉及一个线程,因此不需要同步
  • 在极少数情况下,StringBuffer / Builder变量是一个字段并且在线程间共享,StringBuffer保证可能不够,因为每次调用{{1将随机排序

想象:

append

public void m(String a, String b) { sharedStringBuffer.append(a).append(b); } 并不能保证每次调用m都会导致StringBuffera相邻,因为另一个追加调用可能发生在中间...

所以底线:

  • 不共享变量:使用b
  • 它是共享的,您可能需要的不仅仅是StringBuilder的同步:使用StringBuffer进行适当的同步。

答案 4 :(得分:0)

当你有一个在线程之间共享的StringBuffer时,你应该关心它。如果您没有共享,那么就不会发生竞争条件,您可以自由使用StringBuilder。

答案 5 :(得分:0)

以这种方式思考。让我们假设您有一个类,它在它的方法之间共享一个StringBuilder实例。像这样:

public class MyClass {
    private StringBuilder str = new StringBuilder();

    public void add(String str) {
         this.str.append(str);
    }

    public void remove(int start, int end) {
         this.str.delete(start, end);
    }

}

因为此实例是非同步方法之间的共享,所以如果两个线程同时调用此方法,则数据不会是您期望的数据。这是不保证同步的意思。

您可以使用支持同步的StringBuffer,而不是使用StringBuilder。

public class MyClass {
    private StringBuffer str = new StringBuffer();

    public void add(String str) {
         this.str.append(str);
    }

    public void remove(int start, int end) {
         this.str.delete(start, end);
    }

}

如您所知,同步存在一些性能问题,但在多线程情况下是必要的。

通常StringBuilder可以用作局部变量。

答案 6 :(得分:0)

除非您在线程之间共享StringBuffer,否则不需要StringBuffer,在这种情况下,同步是有意义的。 StringBuilder是可变的,这意味着它的状态可以在线程之间不一致地查看。 StringBuffer没有遇到这个问题(根本不需要)。

StringBuilder就像StringBuffer v2。在开发人员对线程安全性和在不需要线程安全性时需要线程安全的阶段之后,它被添加到Java库中。

至于您发布的javadoc的粗体部分,同步有开销,并且因为StringBuilder是非同步的,所以不会影响性能。

同步保证意味着因为它与StringBuffer"兼容,你可能会期望StringBuilder同步,但可能不是这种情况(例如JIT时)例如,优化StringBuffer。

您不必担心无保证或保证同步。你应该担心的是在共享时使用StringBuffer。无论StringBuilder是同步还是未同步,只要它只在一个线程内共享或相应地受到保护,就不应该遇到任何问题。

你应该担心在这里使用StringBuffer:

final StringBuffer append = new StringBuffer();

void append() {
    append.append(". ");
}

new Thread(() -> append()).start();
new Thread(() -> append()).start();

您可以看到它是由两个线程访问的。注意它是如何声明最终的初始化安全性。