StringBuffer
との主な違いは何StringBuilder
ですか? これらのいずれかを決定する際にパフォーマンスの問題はありますか?
32 に答える
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);
}
}
}
テストの実行により、 forと2241 ms
forの数値が得られます。StringBuffer
753 ms
StringBuilder
基本的に、StringBuffer
メソッドは同期されますが、そうでStringBuilder
はありません。
操作は「ほぼ」同じですが、単一のスレッドで同期メソッドを使用するのはやり過ぎです。
それはほとんどそれについてです。
StringBuilder APIからの引用:
このクラス [StringBuilder] は、StringBuffer と互換性のある API を提供しますが、同期の保証はありません。このクラスは、文字列バッファーが単一のスレッドによって使用されていた場所 (一般的なケース) で、StringBuffer のドロップイン置換として使用するように設計されています。可能であれば、このクラスを StringBuffer よりも優先して使用することをお勧めします。これは、ほとんどの実装でより高速になるためです。
そこで代用するようにしました。
Vector
とについても同じことが起こりましたArrayList
。
しかし、例の助けを借りて明確な違いを得る必要がありますか?
StringBuffer または StringBuilder
StringBuilder
スレッド間でバッファを共有しようとしている場合を除き、単純に使用してください。元の同期クラスStringBuilder
の非同期 (オーバーヘッドが少ない = 効率的) 弟です。StringBuffer
StringBuffer
最初に来ました。Sun はすべての条件下での正確性に関心を持っていたため、万が一に備えてスレッドセーフにするために同期化を行いました。
StringBuilder
後で来ました。の使用のほとんどStringBuffer
はシングル スレッドであり、同期のコストを不必要に支払っていました。
StringBuilder
は同期なしのドロップイン置換であるためStringBuffer
、どの例にも違いはありません。
スレッド間で共有しようとしている場合はStringBuffer
、 を使用できますが、より高レベルの同期が必要かどうかを検討してください。たとえば、StringBuffer を使用する代わりに、StringBuilder を使用するメソッドを同期する必要があります。
最初に類似点を見てみましょう: StringBuilder と StringBuffer は両方とも変更可能です。つまり、同じ場所でそれらの内容を変更できます。
相違点: StringBuffer は可変であり、同期もされています。StringBuilder は変更可能ですが、デフォルトでは同期されません。
同期の意味 (同期) : 何かが同期されると、複数のスレッドがアクセスして、問題や副作用なしで変更できます。StringBuffer は同期されるため、複数のスレッドで問題なく使用できます。
いつ使う? StringBuilder : 変更可能な文字列が必要で、1 つのスレッドのみがそれにアクセスして変更している場合。StringBuffer : 変更可能な文字列が必要で、複数のスレッドがそれにアクセスして変更している場合。
注: StringBuffer を不必要に使用しないでください。つまり、1 つのスレッドのみが変更およびアクセスしている場合は使用しないでください。これには、CPU 時間を不必要に消費する同期用のロックおよびロック解除コードが多数含まれているためです。必要でない限り、ロックを使用しないでください。
シングル スレッドでは、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 !
したがって、ビルダーはバッファーよりも高速であり、文字列の連結よりもはるかに高速です。次に、複数のスレッドに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 ミリ秒かかります。同じテストではありませんが、前の 37 ミリ秒と比較すると、マルチスレッドの使用により StringBuffers の追加が遅くなっていることは間違いありません。その理由は、ロックをチェックする必要がないことを検出すると、JIT/ホットスポット/コンパイラ/何かが最適化を行うためです。
しかし、StringBuilder では、同時スレッドが追加すべきではない場所に何かを追加しようとするため、 java.lang.ArrayIndexOutOfBoundsException が発生します。
結論として、StringBuffer を追跡する必要はありません。スレッドがある場合は、数ナノ秒を取得しようとする前に、スレッドが何をしているのかを考えてください。
StringBuilder は Java 1.5 で導入されたため、以前の JVM では機能しません。
Javadocから:
StringBuilder クラスは、StringBuffer と互換性のある API を提供しますが、同期の保証はありません。このクラスは、文字列バッファーが単一のスレッドによって使用されていた場所 (一般的なケース) で、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.
よくあること :-
どちらも同じ署名を持つ同じメソッドを持っています。どちらも可変です。
StringBuffer
- 同期されているためスレッドセーフ
- スレッドセーフのため遅い
StringBuilder
- Java 5.0 で導入
- 非同期であるため高速で効率的
- ユーザーは、必要に応じて明示的に同期する必要があります
StringBuffer
他の変更なしで置き換えることができます
StringBuilder
とStringBuffer
ほとんど同じです。違いは、同期されているのStringBuffer
と同期されStringBuilder
ていないということです。StringBuilder
はより高速ですが、StringBuffer
パフォーマンスの違いはごくわずかです。StringBuilder
のSUNの代替品ですStringBuffer
。すべてのパブリックメソッドからの同期を回避するだけです。それどころか、それらの機能は同じです。
良い使い方の例:
テキストが変更され、複数のスレッドで使用される場合は、を使用することをお勧めしますStringBuffer
。テキストが変更されるが、単一のスレッドで使用される場合は、を使用しますStringBuilder
。
String
不変です。
StringBuffer
可変で同期されています。
StringBuilder
も変更可能ですが、同期されていません。
javadocは違いを説明しています:
このクラスは、StringBuffer と互換性のある API を提供しますが、同期は保証されません。このクラスは、文字列バッファーが単一のスレッドによって使用されていた場所 (一般的なケース) で、StringBuffer のドロップイン置換として使用するように設計されています。可能であれば、このクラスを StringBuffer よりも優先して使用することをお勧めします。これは、ほとんどの実装でより高速になるためです。
StringBuilder
StringBuffer
(Java 5 で導入) は、メソッドが同期されないことを除いて、と同じです。これは、後者よりもパフォーマンスが優れていることを意味しますが、スレッドセーフではないという欠点があります。
詳細については、チュートリアルを参照してください。
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 は可変です。長さや内容によって変わる場合があります。StringBuffer はスレッドセーフです。つまり、一度に 1 つのスレッドだけが StringBuffer オブジェクトの同期されたコードにアクセスできるように、アクセスを制御する同期メソッドがあります。したがって、StringBuffer オブジェクトは、複数のスレッドが同時に同じ StringBuffer オブジェクトにアクセスしようとする可能性があるマルチスレッド環境で安全に使用できます。
StringBuilder StringBuilder クラスは StringBuffer と非常によく似ていますが、アクセスが同期されないためスレッドセーフではない点が異なります。同期しないことで、StringBuilder のパフォーマンスは StringBuffer よりも向上する可能性があります。したがって、シングルスレッド環境で作業している場合、StringBuffer の代わりに StringBuilder を使用すると、パフォーマンスが向上する可能性があります。これは、1 つのスレッドのみが StringBuilder オブジェクトにアクセスする StringBuilder ローカル変数 (つまり、メソッド内の変数) などの他の状況にも当てはまります。
AString
は不変オブジェクトです。つまり、値は変更できませんが、StringBuffer
可変です。
はStringBuffer
同期化されているため、スレッドセーフStringBuilder
ではありませんが、シングルスレッドのインスタンスにのみ適しています。
同期さStringBuilder
れず、パフォーマンスが向上するため、より適切に使用できます。古い のドロップイン交換です。StringBuilder
StringBuffer
StringBuffer は、変更される文字列を格納するために使用されます (String オブジェクトは変更できません)。必要に応じて自動的に拡張されます。関連クラス: String、CharSequence。
StringBuilder は Java 5 で追加されました。同期されないことを除いて、すべての点で StringBuffer と同じです。つまり、複数のスレッドが同時にアクセスすると、問題が発生する可能性があります。最も一般的なシングルスレッド プログラムの場合、同期のオーバーヘッドを回避すると、StringBuilder がわずかに高速になります。
StringBuffer
同期されていますが、同期されていStringBuilder
ません。その結果、StringBuilder
は よりも高速ですStringBuffer
。
StringBuilder
と の間に基本的な違いはありませんStringBuffer
。わずかな違いしかありません。メソッドでStringBuffer
同期されます。これは、一度に 1 つのスレッドしか操作できないことを意味します。複数のスレッドがある場合、2 番目のスレッドは最初のスレッドが終了するまで待機する必要があり、3 番目のスレッドは最初と 2 番目のスレッドが終了するまで待機する必要があります。これにより、プロセスが非常に遅くなり、パフォーマンスが低下しStringBuffer
ます。
一方、StringBuilder
同期されていません。これは、一度に複数のスレッドが同じStringBuilder
オブジェクトに対して同時に操作できることを意味します。これにより、プロセスが非常に高速になり、パフォーマンスが向上しStringBuilder
ます。
主な違いはStringBuffer
同期化されていますが、StringBuilder
そうではありません。複数のスレッドを使用する必要がある場合は、StringBuffer をお勧めします。ただし、同期化されていないため、実行速度StringBuilder
は よりも高速ですStringBuffer
。
String vs StringBuffer vs 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");
}
結果:
1 つのテキストを追加するための 100000 回の反復
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
1 つのテキストを追加するための 10000 回の反復
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
- StringBuffer はスレッドセーフですが、StringBuilder はスレッドセーフではありません。
- StringBuilder は StringBuffer よりも高速です。
- StringBuffer は同期されますが、StringBuilder は同期されません。
StringBuffer に存在するすべてのメソッドは Synchronized です。したがって、一度に 1 つのスレッドだけが StringBuffer オブジェクトを操作できます。この問題を克服するために、スレッドの待機時間が増加し、パフォーマンスの問題が発生します。SUN People は、バージョン 1.5 で StringBuilder を導入しました。