1

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();
}
4

4 に答える 4

4

StringBufferJDK 1.0から存在しています。

Field1.4.2 より前に登場しました。

ついにJava 1.5StringBuilderで道を拓きました。

于 2012-08-10T21:50:01.307 に答える
4

主な理由は、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();
}

100 万の長さの文字列と 1000 回の繰り返しにより、上記のコードは私のマシンで 8 秒で実行されます。ただし、ローカル変数ではなくフィールドにすると、約 13 秒かかります (JVM は、1 つのスレッドのみがアクセスするbufferことを簡単に保証できなくなったため)。buffer

于 2012-08-10T21:51:24.127 に答える
2

記憶が正しければ、Stringbuffer が最初に導入されたので、これは古いコードである可能性があります。本当の理由はスレッドセーフでなければなりませんが、バッファは安全ですが、stringbuilder は安全ではありません。

于 2012-08-10T21:44:25.323 に答える
1

私は何人かの JVM 開発者に会って、8 年前に一時的な代替手段として StringBuilder に移行することを推奨して以来、なぜ StringBuffer がまだ多く使用されているのかを尋ねました。彼らが心配したり考えたりしたことではないという印象を受けました。プロダクト マネージャーの 1 人からの正式な理由はありませんでした。

Java Coding Convention (1999) でスペースを使用するように提案されたときに、JDK ソースがタブを使用する理由はそこにあると思います。修正はコード フォーマッタを使用した簡単なものですが、誰の todo リストにも載っていません。


IMHO StringBuffer は、そもそもマルチスレッド化するのは良い考えではありませんでした。まれに、マルチスレッドの方法でメモリ内の文字ストリームに書き込みたい場合があり、生成されたテキストがどれほどごちゃごちゃになっていても気にしません。 Java 1.0 で使用可能) または StringBuilder を同期します。

実際には、SimpleDateFormat がそれを使用し、スレッドセーフではないにもかかわらず、StringBuffer をある程度使用しているなど、実際には多くのバグが発生していると思います。一部の開発者は、スレッド セーフなコレクションを使用することで誤ったセキュリティ意識を持ったり、スレッド セーフに見えたりした可能性があります。つまり、複数のスレッドで StringBuilder ではなく StringBuffer を使用すると、バグがある可能性があるとしても、簡単なテストに合格する可能性が高くなります。

例: 2 つのスレッドの書き込みを検討してください

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

問題は、それぞれappendが同期されている一方で、コードの各ブロックが同期されていないことです。あなたが得ることができるので

Hello Hello World World\n\n

また

Hello World Hello \nWorld\n

したがって、StringBuffer は、append を 1 回しか使用しない場合、同期なしでのみスレッドセーフであり、無意味になります。


StringBuffer に関する質問が SO に投稿されたときに切り替えるように人々に指摘するようにしています。

于 2012-08-11T07:19:41.153 に答える