2012-08-09 41 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