Java:使用同步集合的经验法则?

时间:2012-08-09 16:12:49

标签: java collections synchronize

我正在阅读关于使用StringBuilder与StringBuffer的Stackoverflow thread

底线似乎是两个集合是相同的,除了StringBuffer是同步的,是一个线程安全的,并且与StringBuilder相比性能稍差,而不是那些东西。

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

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

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

只要我不故意创建新线程,我是否可以安全地使用非同步集合?

7 个答案:

答案 0 :(得分:5)

使用不同步的内容,直到您确定需要同步为止。

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

当您知道自己正在使用并发和多线程时,请计算出所需的同步详细信息,但只需将StringBuffer换成StringBuilder只会给您一种错误的安全感 - 即使您决定稍后使用并发,也不一定是并发的

(如果您当前没有使用线程,那么绝对没问题 - 甚至建议 - 查找并替换StringBufferStringBuilder。上述参数用于反向。 )

答案 1 :(得分:1)

我会说在你知道如何自己回答这个问题之前,总是使用非阻塞的东西。它很容易同步一切,它也非常容易创建和启动线程。需要一段时间才能了解何时使用synchronized以及何时创建线程。

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

我们正在使用StringBuilder而不是StringBuffer,因为我们认为多线程不会导致我们出现问题。

答案 4 :(得分:0)

在没有进一步分析的情况下,在整个代码库上执行此操作会自动听起来有点危险,除非您100%肯定这些对象(Vectors,StringBuffers)不是在线程之间共享,或者是否未选择同步对象首先通过线程安全分析。

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

答案 5 :(得分: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”。即便如此,您可能会发现使用自己的锁定更容易/更有效。

... IMHO

答案 6 :(得分: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();
  }

在上文中,StringBuilder中的sb永远不会被另一个线程看到,因此无需同步它。