始めに
「StringBuilderとStringBufferの違いを説明してください。」
と言われ、
「StringBuilderの方がパフォーマンス良いです!!」
としか答えられなかった。
なので今回はなぜStringBuilderがパフォーマンスが良いのか、速度の差はどれぐらいなのかを検証してみました。
違う所
StringBuilder:スレッドセーフじゃない
StringBuffer:スレッドセーフ
これだけでした。
StringBuilderを導入したTigerさんによると、
「文字列連結にスレッドセーフって必要?」
という考えで作られたらしいです。
文字列操作 スレッドセーフ vs パフォーマンス StringBuilder
確かに私もスレッドセーフが必要な文字列連結なんて見たことありません。
多くの人があまり気にせず使ってた所でしょうが、そこを捉えたのはすごいと思います。
検証
早速簡単に検証をしてみました。
こちらの検証方法を採用させていただきました。
【Java】StringBuilderとStringBufferの違いをスレッドセーフの観点で検証してみた
100スレッドで同じStringBuilder / StringBufferのインスタンスを共有、1万回appendを繰り返します。
結果、length()が正しく100万になるかを見ています。
処理速度も測定しました。
※StringBuilderとStringBufferの違いだけのソースになります。
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;
}
}
}
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使うかなと思います。