8

StringBuffer と StringBuilder の違いを知っています。ここを読んでください

そして一般的に、javadocが言うように、

可能であれば、このクラスを StringBuffer よりも優先して使用することをお勧めします。これは、ほとんどの実装でより高速になるためです。

ただし、StringBuilder の javadoc にも次のように記載されています。

のインスタンスはStringBuilder、複数のスレッドで安全に使用できません。このような同期が必要な場合は、{@link java.lang.StringBuffer} を使用することをお勧めします

では、StringBuffer が優先されるケースは本当に存在するのでしょうか? そして、変更可能な文字列は主に単一のスレッドで使用されるため、StringBuffer が優先されるという同時現実世界のシナリオを誰かに教えてもらえますか?

4

4 に答える 4

7

StringBuffer がスレッドセーフである理由は、Java API の最初のバージョンが設計された当時、人々は現在とは異なる方法で並行性にアプローチしたためです。Java はスレッドをサポートしており、複数のスレッドで任意の JDK クラスを使用する可能性があるため、オブジェクトはスレッド セーフであるべきだというのが一般的な意見でした。その後、Java が実行時間の最適化を開始したときに、これらの不要な同期ブロックのコストが問題になり始めたため、新しい API は同期されないように設計されました。さらにその後、JVM はロックの最適化を開始し、競合していないロックが実質的に無料になるまでロックを最適化し、決定全体が議論の余地のあるものになりました。

StringBuffer は、古いコードがスレッドセーフであることに依存している可能性があるため、依然としてスレッドセーフです。これは通常の使用法とはかけ離れていますが、考えられることです。

たとえば、ログ エントリを中央サーバーに転送するログ ファイル アペンダーを作成しているとします。ネットワーク I/O を待っている間、呼び出し元をブロックしたくないので、専用スレッドでそれを行います。他のスレッドは、ログ エントリを StringBuffer に蓄積します。

class RemoteLogger implements Runnable, Appender {
    final StringBuffer buffer = new StringBuffer();

    void append(String s) {
        buffer.append(s);
    }

    public void run() {
        for (;;) {
            Thread.sleep(100);

            String message = buffer.toString();
            sendToServer(message);
            buffer.delete(0, message.length());
        }
    }
}
于 2013-05-20T17:10:27.670 に答える
2

次のプログラムは、StringBuilder を使用すると例外をスローすることがありますが、StringBuffer を使用すると例外をスローしません。

プログラム:

public class StringBuilderConcurrent {
    static final StringBuilder sb = new StringBuilder(); // shared memory

    public static void main(String[] args) throws Exception {
        int NUM_WRITERS = 300;
        ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS);
        for (int i = 0; i < NUM_WRITERS; i++) {
            WriterThread wt = new WriterThread("writerThread" + i);
            threads.add(wt);
            wt.start();
        }
        for (int i = 0; i < threads.size(); i++) {
            threads.get(i).join();
        }    
        System.out.println(sb);
    }

    public static class WriterThread extends Thread {
        public WriterThread(String name) {
            super(name);
        }
        public void run() {
            String nameNl = this.getName() + "\n";
            for (int i = 1; i < 20; i++) {
                sb.append(nameNl);
            }
        }
    };
}

StringBuilder ( sb) はスレッド セーフではないため、複数のスレッドがデータを書き込むと、データが破損するsb可能性がありsbます (予期しない null 文字、単語の文字が他の単語の文字に散在するなど)。のsb内部状態が矛盾して、例外がスローされる可能性もあります。

Exception in thread "writerThread0" java.lang.ArrayIndexOutOfBoundsException
    at java.lang.System.arraycopy(Native Method)
    at java.lang.String.getChars(String.java:854)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391)
    at java.lang.StringBuilder.append(StringBuilder.java:119)
    at test.StringBuilderConcurrent$WriterThread.run(StringBuilderConcurrent.java:35)

次のプログラムは、StringBuilder の代わりに StringBuffer を使用する点を除いて、最初のプログラムと同じです。ArrayIndexOutOfBoundsException が発生することはありません。

public class StringBufferConcurrent {
    static final StringBuffer sb = new StringBuffer(); // shared memory

    public static void main(String[] args) throws Exception {
        int NUM_WRITERS = 300;
        ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS);
        for (int i = 0; i < NUM_WRITERS; i++) {
            WriterThread wt = new WriterThread("writerThread" + i);
            threads.add(wt);
            wt.start();
        }
        for (int i = 0; i < threads.size(); i++) {
            threads.get(i).join();
        }

        System.out.println(sb);
    }

    public static class WriterThread extends Thread {
        public WriterThread(String name) {
            super(name);
        }
        public void run() {
            String nameNl = this.getName() + "\n";
            for (int i = 1; i < 20; i++) {
                sb.append(nameNl);
            }
        }
    };
}

これらのプログラムが「現実世界」の問題を表しているかどうかは、かなり主観的な問題です。その判断は視聴者に委ねます。

于 2013-05-20T16:55:39.780 に答える