LoginSignup
22
17

More than 5 years have passed since last update.

StringBuilderとStringBufferの違い

Last updated at Posted at 2018-07-29

始めに

「StringBuilderとStringBufferの違いを説明してください。」
と言われ、
「StringBuilderの方がパフォーマンス良いです!!」
としか答えられなかった。

なので今回はなぜStringBuilderがパフォーマンスが良いのか、速度の差はどれぐらいなのかを検証してみました。

違う所

StringBuilder:スレッドセーフじゃない
StringBuffer:スレッドセーフ

これだけでした。
StringBuilderを導入したTigerさんによると、
「文字列連結にスレッドセーフって必要?」
という考えで作られたらしいです。

文字列操作 スレッドセーフ vs パフォーマンス StringBuilder

確かに私もスレッドセーフが必要な文字列連結なんて見たことありません。
多くの人があまり気にせず使ってた所でしょうが、そこを捉えたのはすごいと思います。

検証

早速簡単に検証をしてみました。
こちらの検証方法を採用させていただきました。
【Java】StringBuilderとStringBufferの違いをスレッドセーフの観点で検証してみた

100スレッドで同じStringBuilder / StringBufferのインスタンスを共有、1万回appendを繰り返します。
結果、length()が正しく100万になるかを見ています。
処理速度も測定しました。

※StringBuilderとStringBufferの違いだけのソースになります。

StringBuilderTest.java
public class StringBuilderTest {

    public static void main (String... args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(100);
        StringBuilder sb = new StringBuilder();
        List<BuilderTask> taskList = new ArrayList<BuilderTask>();

        for(int i = 0; i < 100; i++) {
            taskList.add(new BuilderTask(sb));
        }

        Long start = System.currentTimeMillis();

        executor.invokeAll(taskList);

        System.out.println("-----StringBuilder-----");
        System.out.println("TAT : " + (System.currentTimeMillis() - start));
        System.out.println("length() : " + sb.length());
    }

    static class BuilderTask implements Callable<Integer> {
        private StringBuilder sb;

        public BuilderTask(StringBuilder sb) {
            this.sb = sb;
        }

        @Override
        public Integer call() throws Exception {
            for(int i = 0; i < 10000; i++) {
                sb.append("#");             
            }
            return null;
        }
    }
}

StringBufferTest.java
public class StringBufferTest {

    public static void main (String... args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(100);
        StringBuffer sb = new StringBuffer();
        List<BufferTask> taskList = new ArrayList<BufferTask>();

        for(int i = 0; i < 100; i++) {
            taskList.add(new BufferTask(sb));
        }

        Long start = System.currentTimeMillis();

        executor.invokeAll(taskList);

        System.out.println("-----StringBuffer-----");
        System.out.println("TAT : " + (System.currentTimeMillis() - start));
        System.out.println("length() : " + sb.length());
    }

    static class BufferTask implements Callable<Integer> {
        private StringBuffer sb;

        public BufferTask(StringBuffer sb) {
            this.sb = sb;
        }

        @Override
        public Integer call() throws Exception {
            for(int i = 0; i < 10000; i++) {
                sb.append("#");             
            }
            return null;
        }
    }
}

結果

-----StringBuilder-----
TAT : 32
length() : 542861

-----StringBuffer-----
TAT : 157
length() : 1000000

StringBuilderだと文字がほぼ半分ぐらい失われた結果になりました。
代わりに処理速度は5倍ぐらい早いですね。

私はやはり実業務でスレッドセーフな文字列連結が必要な場合は考えにくいので、パフォーマンス重視でStringBuilder使うかなと思います。

22
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
17