簡體   English   中英

當StringBuilder更快時,為什么Java使用StringBuffer(同步)?

[英]Why Java uses StringBuffer (synchronized) when StringBuilder is faster?

我正在查看Java反射類,並注意到了這段代碼。 我想知道,當StringBuilder更快時,為什么Java使用StringBuffer?

Java不想使用最快的實現,還是有其他原因?

該代碼在Field.class中:

static String getTypeName(Class<?> type) {
    if (type.isArray()) {
        try {
            Class<?> cl = type;
            int dimensions = 0;
            while (cl.isArray()) {
                dimensions++;
                cl = cl.getComponentType();
            }
            StringBuffer sb = new StringBuffer();
            sb.append(cl.getName());
            for (int i = 0; i < dimensions; i++) {
                sb.append("[]");
            }
            return sb.toString();
        } catch (Throwable e) { /*FALLTHRU*/ }
    }
    return type.getName();
}

JDK 1.0開始, StringBuffer就出現了。

1.4.2之前出現了Field

最終, StringBuilder進入Java 1.5

主要原因是JVM具有先進的技術,可以查看是否可以避免執行上下文暗示的所有事情。 由於StringBuffer是一個永遠不會逸出該方法的局部變量,因此JVM可以安全地避免在進入StringBuffer的同步方法之前必須嘗試獲取該對象的鎖-因為沒有其他線程能夠調用該特定方法StringBuffer的實例。

快速的微基准測試證明了這一點。 buffer一個字段會使以下代碼減慢50%。

private void doTest(String toCopy) {
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < toCopy.length(); i++) {
        buffer.append(toCopy.charAt(i));
    }
    buffer.toString();
}

使用一百萬個長度的字符串和1000次重復,以上代碼在我的機器上運行8秒鍾。 但是,一旦將buffer為字段而不是局部變量,則將花費約13秒的時間(因為JVM不再能夠輕松保證buffer只能由一個線程訪問)。

如果對我有用的話,首先會介紹Stringbuffer,所以這可能是一段較舊的代碼。 真正的原因必須是線程安全,盡管在緩沖區是stringbuilder時不是安全的。

我見過面並問了幾個JVM開發人員,為什么仍然使用StringBuffer如此之多,因為他們建議人們在8年前取代替代品而遷移到StringBuilder。 我覺得這不是他們擔心/想到的事情。 產品經理之一沒有任何正式理由。

我認為為什么Java編碼約定(1999)建議您使用空格時JDK源代碼使用制表符。 使用代碼格式化程序可輕松解決此問題,但在任何人的待辦事項列表中都不會發現。


恕我直言,StringBuffer從來就不是使多線程成為一個好主意的主意。 在極少數情況下,您可能想以多線程方式寫入內存中的字符流,而不必擔心產生的文本有多混亂,您仍然可以使用更自然的替代方法,例如StringWriter( (在Java 1.0中可用)或同步StringBuilder。

我相信它實際上解決了許多錯誤,例如SimpleDateFormat使用了它,並且即使它不是線程安全的,在某種程度上仍然使用StringBuffer。 可能使用線程安全集合給某些開發人員一種錯誤的安全感,或者看起來有些線程安全。 即在多個線程中使用StringBuffer而不是StringBuilder更可能通過簡單的測試,即使認為可能存在錯誤。

例如考慮兩個線程編寫

sb.append("Hello ").append("World").append("\n");

問題在於,雖然每個append同步,但每個代碼塊都不同步。 所以你可以得到

Hello Hello World World\n\n

要么

Hello World Hello \nWorld\n

因此,如果只使用一次append,StringBuffer僅是線程安全的,無需同步,這使其毫無意義。


我嘗試指出當涉及StringBuffer的問題發布在SO上時要切換的人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM