2012-08-09 43 views
2

我正在阅读关于使用StringBuilder与StringBuffer的此Stackoverflow threadJava:使用同步集合的经验法则?

底线似乎是这两个集合是相同的东西,除了一个StringBuffer是同步的,是一个线程安全的,并且在性能方面做的不如那些不是那些东西的StringBuilder。

有人提出ArrayList和Vector之间存在类似的关系。

除非我有意识地创建多个线程,否则不使用同步集合(或其他任何东西)是否是一个好的(安全的)经验法则?

换句话说,我得到了“尽可能使用新的StringBuilder”的信息,我想知道的是,我怎么能确定它是可能的?

我是否安全使用非同步集合,只要我没有故意创建新的线程?

+1

您可能打算用StringBuilder替换StringBuffer。换句话说,删除不必要的同步。 – 2012-08-09 16:14:35

回答

5

使用不同步的东西,直到您确定需要同步。

问题的一部分与例如StringBufferVector是他们并不总是以正确的方式同步。对于Vector,并不总是你需要需要使每个操作单独同步;经常你想要的是同步操作块...其中Vector不一定比ArrayListCollections.synchronizedList更好。

当你知道你正在使用并发和多线程,然后解决你需要什么同步的细节,但只是交换StringBufferStringBuilder只会给你一个错误的安全感 - 即使你决定稍后使用并发性,并不一定是合适的种类的并发性。

(如果您目前没有使用线程,那么它的精美绝伦 - 甚至建议。 - 找到并替换StringBufferStringBuilder上述论点是相反方向)

+0

+1 *“即使您稍后决定使用并发性,也不一定是正确的并发性。”* – assylias 2012-08-09 16:21:04

+0

+1 SimpleDateFormat使用StringBuffer,但由于未正确实施,因此不是线程安全的。 – 2012-08-09 17:56:16

0

我们使用StringBuilder而不是StringBuffer,因为我们不认为多线程会导致我们遇到问题。

0

在整个代码库上执行它自动听起来有点危险,没有进一步分析,除非您100%肯定这些对象(Vectors,StringBuffers)没有跨线程共享,或者如果选择的同步对象不是首先由线程安全分析驱动。

一个简单的情况,你可以在没有风险的情况下进行交换,它是局部变量,显然不能在线程间共享(除非你返回它们)。

+0

好点。我认为我所有的StringBuffers都存在于函数中,所以它们都是局部变量。 – Steve 2012-08-09 16:17:02

1

我会说永远使用无阻塞任何东西,直到你知道如何自己回答这个问题。同步所有内容非常简单,它也非常易于创建和启动线程。理解何时使用同步以及何时创建线程需要一段时间。

您应该首先阅读Java Concurrency in Practice。

+0

是否有可能在不知道我这样做的情况下启动新线程(即编写新的线程())?如果我不这样做,我可以安全地使用非同步集合吗? – Steve 2012-08-09 16:20:19

+1

除非你创建一个'new Thread'或者使用'ExecutorService'并且你自己编写所有的代码,否则你不需要同步任何东西。唯一的例外是如果你正在创建一个Swing应用程序。有了这个例外,这将是罕见的。 – 2012-08-09 16:23:16

+0

这真的取决于。如果您使用的是第三方库,您将某些侦听器和/或回调传递给它,可以很好地在不同的线程上调用它们。 – 2012-08-09 16:24:02

0

此链接最好说它:

* http://javahowto.blogspot.com/2006/08/stringbuilder-vs-stringbuffer.html

StringBuilder的是在JDK 1.5引入的。 StringBuilder和StringBuffer有什么区别?根据javadoc的说法,StringBuilder是 ,被设计为单线程用法中的StringBuffer的替代品。 他们在简单的短期关键区别:

  • StringBuffer的被设计为线程安全的,而StringBuffer的所有公共方法是同步的。 StringBuilder不处理线程安全问题 并且它的任何方法都不同步。

  • 在大多数情况下,StringBuilder比StringBuffer具有更好的性能。

  • 尽可能使用新的StringBuilder。

从我自己的经验:

  • 对于任何严肃的字符串操作,始终使用StringBuilder(从来没有 “串”)

  • 我从来没有在任何场合使用StringBuffer(我总是只使用“StringBuilder”)。

  • 只有当相同字符串正在进行正在同时从多个线程访问,你应该甚至考虑“的StringBuffer”。即使如此,你可能会发现使用自己的锁更容易/更高效。

恕我直言...

+0

我认为这个问题要求澄清*“尽可能使用新的StringBuilder”*,即如何确保它是可能的。 – assylias 2012-08-09 16:18:21

+0

的确,我正在将你的短语放入我的问题中。清楚并且重点,谢谢。 – Steve 2012-08-09 16:22:04

+0

上面隐含了两条经验法则:1)如果没有线程:不要担心。使用StringBuilder;)2)如果你有线程...但是进行中的字符串是一个局部变量:不要担心;)。另外:如果你认为自己可以更好地完成锁定 - 那就去做吧。使用StringBuilder。清楚;)? – paulsm4 2012-08-09 16:26:51

1

它看起来像你问多个问题在这里。所以,首先,除非绝对必要,否则避免同步确实是一个好主意。

在第二个问题上,将StringBuilder替换为StringBuffer也是安全的,反之亦然,除非它们的值可以从多个线程中更改。

+0

好点,我删除了第二个辅助问题。 – Steve 2012-08-09 16:21:13

0

除非我有意识地创建多个线程,否则不要使用同步集合(或其他任何东西)是一种好的(安全的)经验法则?

不,它不是。

有些情况下涉及多个线程,即使您不自觉地创建它们。例如,使用Swing或Servlet的任何应用程序都有可能在不同线程上的应用程序代码之间进行交互。 (你甚至可以争辩说,如果你使用标准的线程池实现,你不会明确创建线程。)

此外,使用同步收集不一定会为您购买线程安全。

但是,在使用数据结构的多线程不可能使用数据结构时使用同步数据结构的意义是有些浪费的。但是就像在过去当互斥体昂贵时那样浪费。


换句话说,我得到的消息,“只要有可能使用新的StringBuilder。”,我想知道的是,我怎么能肯定这是可能的吗?

通过理解你的代码。 StringBuilder可以被其他线程看到吗?如果不是,那么它可以安全地使用它。否则,共享StringBuilder的线程需要同步。一种方法做到这一点可能是使用StringBuffer,但不会必然给你正确的同步粒度。

这里有一个简单的例子:

public String nTimes(String str, int n) { 
     StringBuilder sb = new StringBuilder(); 
     for (int i = 1; i <= n; i++) sb.append(str); 
     return sb.toString(); 
    } 

在上面,在sbStringBuilder永远不能被其他线程可以看到,所以没有必要进行同步。

+0

我知道JSP只是Servlet,但我可以安全地使用JSP中的非同步集合?什么是Servlets使用的类?在像Spring这样的框架中编写函数怎么样? – Steve 2012-08-09 16:32:37

+0

@Steve - 答案是“它取决于”。如果涉及的对象是线程受限的,则是安全的。否则,推广过于复杂。 – 2012-08-09 16:38:13

+0

如何知道我的代码是否可以被其他线程看到?我没有故意创建任何线程。除了Servlet和Swing之外,有没有其他情况会导致问题? – Steve 2012-08-09 16:39:04