StringBuffer
とStringBuilder
の主な違いは何ですか?これらのいずれかを決定する際にパフォーマンス上の問題はありますか?
StringBuffer
は同期されますが、 StringBuilder
は同期されません。
StringBuilder
はStringBuffer
ではないので synchronized
より速いです。
これは簡単なベンチマークテストです。
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
テスト実行 はStringBuffer
に対する2241 ms
とStringBuilder
に対する753 ms
の数を与えます。
基本的にStringBuffer
メソッドは同期されますがStringBuilder
は同期されません。
操作は「ほぼ」同じですが、単一スレッドで同期メソッドを使用するのはやり過ぎです。
それはそれについてほとんどです。
このクラス[StringBuilder]はStringBuffer、と互換性のあるAPIを提供しますが、同期の保証はありません。このクラスは、文字列バッファがシングルスレッドによって使用されていた場所でのStringBufferのドロップイン置換として使用するために設計されています(一般的な場合)。可能であれば、このクラスはStringBufferよりもとして優先的に使用することをお勧めします。
それでそれを代用するようにされました。
Vector
とArrayList
でも同じことが起こりました。
しかし、例の助けを借りて明確な違いを得る必要がありますか?
StringBufferまたはStringBuilder
単にスレッド間でバッファを共有しようとしている場合を除き、単にStringBuilder
を使用します。 StringBuilder
は、元の同期StringBuffer
クラスの同期されていない(オーバーヘッドが少ない=より効率的な)弟です。
StringBuffer
が最初に来ました。 Sunはすべての条件下での正確性に関心があったため、万が一に備えてスレッドセーフにするために同期させました。
StringBuilder
は後で来ました。 StringBuffer
の使用のほとんどはシングルスレッドであり、同期のコストを不必要に支払っています。
StringBuilder
はdrop-in replacementであるため、StringBuffer
は同期の場合、どの例にも違いはありません。
areスレッド間で共有しようとしている場合、StringBuffer
を使用できますが、より高いレベルの同期が必要かどうかを検討してください。おそらくStringBufferを使用する代わりに、StringBuilderを使用するメソッドを同期する必要があります。
最初に 類似点を見てみましょう :StringBuilderとStringBufferはどちらも可変です。つまり、同じ場所でそれらのコンテンツを変更できます。
違い :StringBufferは可変で同期もされています。 StringBuilderは変更可能だがデフォルトでは同期されない。
同期された(同期)の意味 :何らかのことが同期されると、複数のスレッドがアクセスしたり、問題や副作用なしにそれを変更したりすることができます。 StringBufferは同期化されているので、問題なく複数のスレッドで使用できます。
いつ使うの? StringBuilder:変更可能な文字列が必要で、それにアクセスして変更しているスレッドが1つだけの場合。 StringBuffer:変更可能な文字列が必要で、複数のスレッドがそれにアクセスして変更している場合。
注 :StringBufferを不必要に使用しないでください。つまり、1つのスレッドだけがそれを変更およびアクセスしている場合は使用しないでください。必要な場合以外はロックを使用しないでください。
JVM最適化のおかげで、シングルスレッドでは、StringBufferはStringBuilderよりもそれほど遅くはありません _です。そしてマルチスレッドでは、StringBuilderを安全に使用することはできません。
これが私のテストです(ベンチマークではなく、単なるテストです)。
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
結果 :
文字列:319740
バッファ:23
ビルダー:7!
つまり、BuilderはBuffersよりも速く、WAYはストリング連結よりも高速です。それではマルチスレッドにExecutorを使いましょう:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
StringBuffersは100000の追加に対して157 msを使用します。これは同じテストではありませんが、前の37ミリ秒と比較すると、安全にStringBuffersのアペンドはマルチスレッドの使用では遅いと見なすことができます。その理由は、JIT/hotspot/compiler/somethingが no ロックをチェックする必要があることを検出したときに最適化を行うからです。
ただし、StringBuilderでは、Java.lang.ArrayIndexOutOfBoundsExceptionがあります _は、並行スレッドが本来あるべき場所に追加しようとしているためです。
結論としては、StringBuffersを追う必要はないということです。そして、あなたがスレッドを持っているところで、数ナノ秒を得ることを試みる前に、それらが何をしているかについて考えてください。
StringBuilderはJava 1.5で導入されたため、以前のJVMでは動作しません。
Javadocs :から:
StringBuilderクラスはStringBufferと互換性のあるAPIを提供しますが、同期の保証はありません。このクラスは、文字列バッファがシングルスレッドによって使用されていた場所でのStringBufferのドロップイン置換として使用するために設計されています(一般的な場合)。可能であれば、このクラスはStringBufferよりも優先して使用することをお勧めします。ほとんどの実装では高速になるからです。
かなり良い質問
ここに違いがあります、私は気づいています:
StringBuffer: -
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder: -
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
一般的なこと: -
どちらも同じシグネチャを持つ同じメソッドを持っています。どちらも変更可能です。
StringBuilder
とStringBuffer
はほぼ同じです。違いは、StringBuffer
は同期され、StringBuilder
は同期されないということです。 StringBuilder
はStringBuffer
より速いですが、パフォーマンスの違いはほとんどありません。 StringBuilder
は、SunがStringBuffer
を置き換えたものです。それだけですべてのパブリックメソッドからの同期を回避します。それよりもむしろ、それらの機能は同じです。
良い使い方の例:
あなたのテキストが変更され、複数のスレッドによって使用される場合は、StringBuffer
を使用することをお勧めします。あなたのテキストを変更しようとしているが単一のスレッドによって使用されている場合は、StringBuilder
を使用してください。
StringBuffer
StringBuilder
StringBuilder
に置き換えられますStringBuffer
StringBufferは可変であるということは、オブジェクトの値を変更できるということです。 StringBufferを通じて作成されたオブジェクトはヒープに格納されます。 StringBufferはStringBuilderと同じメソッドを持ちますが、StringBufferの各メソッドは同期化されている、つまりStringBufferはスレッドセーフです。
このため、2つのスレッドが同時に同じメソッドにアクセスすることは許可されていません。各メソッドは一度に1つのスレッドからアクセスできます。
しかし、スレッドセーフであることには、スレッドセーフなプロパティが原因でStringBufferのパフォーマンスが低下するため、欠点もあります。したがって、各クラスの同じメソッドを呼び出す場合、StringBuilderはStringBufferよりも高速です。
StringBuffer値は変更できます。つまり、新しい値に割り当てることができます。今日、その最も一般的なインタビューの質問、上記のクラス間の違い。 toString()メソッドを使用して文字列バッファを文字列に変換できます。
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilderはStringBufferと同じです。つまり、オブジェクトをヒープに格納し、それを変更することもできます。 StringBufferとStringBuilderの主な違いは、StringBuilderもスレッドセーフではないということです。 StringBuilderはスレッドセーフではないため高速です。
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
String
は不変です。
StringBuffer
は可変で同期されています。
StringBuilder
も可変ですが、同期はされていません。
javadoc は違いを説明します。
このクラスはStringBufferと互換性のあるAPIを提供しますが、同期の保証はありません。このクラスは、文字列バッファがシングルスレッドによって使用されていた場所でのStringBufferのドロップイン置換として使用するために設計されています(一般的な場合)。可能であれば、このクラスはStringBufferよりも優先して使用することをお勧めします。ほとんどの実装では高速になるからです。
(Java 5で導入された)StringBuilder
は、そのメソッドが同期されていないことを除いて、StringBuffer
と同じです。これは後者よりもパフォーマンスが優れていることを意味しますが、欠点はスレッドセーフではないことです。
詳しくは チュートリアル を読んでください。
StringBufferとStringBuilderの違いを説明する簡単なプログラム:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer:
StringBuilder
文字列ビルダー :
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
文字列バッファ
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
StringBufferより速いので、可能な限りStringBuilderを使用することをお勧めします。ただし、スレッドの安全性が必要な場合は、StringBufferオブジェクトが最善の選択肢です。
StringBuilderは同期されていないのでパフォーマンスが向上しているので、StringBuilderを使用してください。 StringBuilderは、古いStringBufferの代わりになるドロップインです。
StringBuffer は可変です。それは長さと内容の点で変わることがあります。 StringBuffersはスレッドセーフです。つまり、アクセスを制御する同期メソッドがあるため、一度に1つのスレッドだけがStringBufferオブジェクトの同期コードにアクセスできます。したがって、StringBufferオブジェクトは一般に、複数のスレッドが同時に同じStringBufferオブジェクトにアクセスしようとしている可能性があるマルチスレッド環境で安全に使用できます。
StringBuilder StringBuilderクラスはStringBufferとよく似ていますが、アクセスが同期されていないためスレッドセーフではありません。同期されないことで、StringBuilderのパフォーマンスはStringBufferよりも優れたものになります。したがって、シングルスレッド環境で作業している場合は、StringBufferの代わりにStringBuilderを使用するとパフォーマンスが向上する可能性があります。これは、StringBuilderオブジェクトにアクセスするスレッドが1つだけになるStringBuilderローカル変数(つまり、メソッド内の変数)などの他の状況にも当てはまります。
StringBuffer
は同期されていますが、StringBuilder
は同期されていません。その結果、StringBuilder
はStringBuffer
より速くなります。
StringBuffer
は同期化されているので、余分な労力を必要とします。したがって、パフォーマンスに基づいて、StringBuilder
よりも少し遅くなります。
StringBuilderとStringBufferの間には基本的な違いはありませんが、違いがいくつかあります。 StringBufferでは、メソッドは同期されています。これは、一度に1つのスレッドしか操作できないことを意味します。複数のスレッドがある場合、2番目のスレッドは最初のスレッドが終了するのを待たなければならず、3番目のスレッドは1番目と2番目のスレッドが終了するのを待つ必要があります。これにより処理が非常に遅くなり、したがってStringBufferの場合のパフォーマンスが低下します。
一方、StringBuilderは非同期です。これは、一度に複数のスレッドが同じStrinBuilderオブジェクトを同時に操作できることを意味します。これはプロセスを非常に速くするので、StringBuilderのパフォーマンスは高いです。
StringBufferは、変更される文字列を格納するために使用されます(Stringオブジェクトは変更できません)。必要に応じて自動的に拡張します。関連クラス:String、CharSequence。
StringBuilderはJava 5で追加されました。同期されない点を除いて、StringBufferとすべての点で同じです。つまり、複数のスレッドが同時にアクセスした場合、問題が発生する可能性があります。シングルスレッドプログラムの場合、最も一般的なケースでは、同期のオーバーヘッドを回避することでStringBuilderが少し速くなります。
主な違いはStringBuffer
は同期されていますがStringBuilder
は同期されていないということです。複数のスレッドを使用する必要がある場合はStringBufferをお勧めします。実行速度の観点からStringBuilder
はStringBuffer
より高速です。
Stringは不変のオブジェクトなので、StringBufferが変更可能な場合は値を変更できません。
StringBuilderはシングルスレッドのインスタンスには適していないため、StringBufferは同期化されているためスレッドセーフです。
StringBuffer
の同期追加メソッドとStringBuilder
の非同期追加メソッドの内部を確認してください。
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
Appendはsynchronized
なので、マルチスレッドのシナリオではStringBuffer
はStrinbBuilder
と比較してパフォーマンスのオーバーヘッドがあります。複数のスレッド間でバッファを共有していない限り、StringBuilder
を使用します。これは、appendメソッドにsynchronized
がないため高速です。
これは、 String vs StringBuffer対StringBuilder のパフォーマンステスト結果です。最後に、StringBuilderがテストに勝利しました。テストコードと結果については下記を参照してください。
コード :
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
結果 :
単一のテキストを追加するための10万回の繰り返し
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
単一のテキストを追加するための10000回の繰り返し
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBufferは同期され、スレッドセーフです。StringBuilderは同期されておらず、高速です。
StringBufferに存在するすべてのメソッドはSynchronizedです。したがって、StringBufferオブジェクトを操作できるのは一度に1つのスレッドだけです。この問題を解決するために、スレッドの待機時間が増え、パフォーマンスの問題が発生します。Sun Peopleは、バージョン1.5でStringBuilderを導入しました。