Разница между StringBuilder и StringBuffer
В чем главное отличие StringBuffer
а также StringBuilder
? Есть ли проблемы с производительностью при выборе любого из них?
38 ответов
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);
}
}
}
Тестовый прогон дает числа 2241 ms
за StringBuffer
против 753 ms
за StringBuilder
,
В принципе, StringBuffer
методы синхронизируются в то время как StringBuilder
не.
Операции "почти" одинаковы, но использование синхронизированных методов в одном потоке является излишним.
Это довольно много об этом.
Цитата из StringBuilder API:
Этот класс [StringBuilder] предоставляет API-интерфейс, совместимый с StringBuffer, но без гарантии синхронизации. Этот класс предназначен для использования в качестве замены для StringBuffer в тех местах, где строковый буфер использовался одним потоком (как это обычно бывает). Там, где это возможно, рекомендуется использовать этот класс вместо StringBuffer, так как он будет быстрее в большинстве реализаций.
Так что это было сделано, чтобы заменить его.
То же самое случилось с Vector
а также ArrayList
,
Но нужно ли получить четкую разницу с помощью примера?
StringBuffer или StringBuilder
Просто использовать StringBuilder
если вы действительно не пытаетесь разделить буфер между потоками. StringBuilder
является несинхронизированным (меньше накладных расходов = более эффективным) младший брат оригинальной синхронизированной StringBuffer
учебный класс.
StringBuffer
пришел первым Sun заботился о корректности при любых условиях, поэтому они сделали его синхронизированным, чтобы на всякий случай сделать его поточно-ориентированным.
StringBuilder
пришел позже Большинство применений StringBuffer
были однопоточными и излишне оплачивали стоимость синхронизации.
поскольку StringBuilder
является заменой для StringBuffer
без синхронизации не было бы различий между примерами.
Если вы пытаетесь поделиться между потоками, вы можете использовать StringBuffer
, но подумайте, необходима ли синхронизация более высокого уровня, например, возможно, вместо использования StringBuffer, если вы синхронизируете методы, которые используют StringBuilder.
Сначала давайте увидим сходство: и StringBuilder, и StringBuffer являются изменяемыми. Это означает, что вы можете изменить их содержимое, находясь в одном месте.
Отличия: StringBuffer изменчив и синхронизирован. Где, так как StringBuilder является изменяемым, но не синхронизируется по умолчанию.
Значение "синхронизированный" (синхронизация): когда что-то синхронизируется, несколько потоков могут получить к нему доступ и изменить его без каких-либо проблем или побочных эффектов. StringBuffer синхронизирован, так что вы можете использовать его с несколькими потоками без каких-либо проблем.
Какой использовать когда? StringBuilder: когда вам нужна строка, которую можно изменить, и только один поток обращается к ней и модифицирует ее. StringBuffer: когда вам нужна строка, которую можно изменить, и несколько потоков обращаются к ней и изменяют ее.
Примечание: не используйте StringBuffer без необходимости, т. Е. Не используйте его, если только один поток модифицирует и обращается к нему, потому что он имеет много кода блокировки и разблокировки для синхронизации, что излишне отнимает время процессора. Не используйте замки, если это не требуется.
В одиночных потоках StringBuffer не намного медленнее, чем StringBuilder, благодаря оптимизации JVM. А в многопоточности вы не можете безопасно использовать 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!
Таким образом, Builders быстрее, чем 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 занимают 157 мс на 100000 операций добавления. Это не тот же тест, но по сравнению с предыдущими 37 мс, вы можете смело предположить, что добавления StringBuffers медленнее при использовании многопоточности. Причина в том, что JIT/hotspot/compiler/ что-то оптимизирует, когда обнаруживает, что нет необходимости проверять блокировки.
Но с StringBuilder у вас есть java.lang.ArrayIndexOutOfBoundsException, потому что параллельный поток пытается добавить что-то, где он не должен.
Вывод: вам не нужно гоняться за StringBuffers. А если у вас есть потоки, подумайте о том, что они делают, прежде чем пытаться набрать несколько наносекунд.
StringBuilder был представлен в Java 1.5, поэтому он не будет работать с более ранними версиями JVM.
Из Javadocs:
Класс StringBuilder предоставляет API-интерфейс, совместимый с StringBuffer, но без гарантии синхронизации. Этот класс предназначен для использования в качестве замены для 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.
Общая вещь:-
Оба имеют одинаковые методы с одинаковыми сигнатурами. Оба изменчивы.
StringBuffer
- Синхронизированный следовательно потокобезопасный
- поток безопасен, следовательно, медленный -
StringBuilder
- Представлено в Java 5.0
- Асинхронный, следовательно, быстрый и эффективный
- Пользователю явно нужно его синхронизировать, если он хочет
- Вы можете заменить это будет
StringBuilder
без каких-либо других изменений
StringBuffer
StringBuffer является изменяемым, что означает, что можно изменить значение объекта. Объект, созданный с помощью StringBuffer, хранится в куче. StringBuffer имеет те же методы, что и StringBuilder, но каждый метод в StringBuffer синхронизирован, то есть StringBuffer является потокобезопасным.
из-за этого он не позволяет двум потокам одновременно обращаться к одному и тому же методу. Каждый метод может быть доступен по одному потоку за раз.
Но безопасность потоков также имеет недостатки, так как производительность 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
StringBuilder не является потокобезопасным. String Buffer есть. Больше информации здесь.
РЕДАКТИРОВАТЬ: Что касается производительности, после запуска горячей точки, StringBuilder является победителем. Однако для небольших итераций разница в производительности незначительна.
StringBuilder
а также StringBuffer
почти одинаковы. Разница в том, что StringBuffer
синхронизируется и StringBuilder
не является. Хотя, StringBuilder
быстрее чем StringBuffer
Разница в производительности очень мала. StringBuilder
является заменой СОЛНЦА StringBuffer
, Он просто избегает синхронизации со всеми общедоступными методами. Вместо этого их функциональность одинакова.
Пример хорошего использования:
Если ваш текст будет меняться и используется несколькими потоками, то лучше использовать StringBuffer
, Если ваш текст собирается измениться, но используется одним потоком, используйте StringBuilder
,
String
является неизменным.
StringBuffer
является изменчивым и синхронизированным.
StringBuilder
также изменчив, но не синхронизирован.
Javadoc объясняет разницу:
Этот класс предоставляет API-интерфейс, совместимый с StringBuffer, но без гарантии синхронизации. Этот класс предназначен для использования в качестве замены для StringBuffer в тех местах, где строковый буфер использовался одним потоком (как это обычно бывает). Там, где это возможно, рекомендуется использовать этот класс вместо StringBuffer, так как он будет быстрее в большинстве реализаций.
StringBuilder
(введено в Java 5) идентично StringBuffer
кроме его методов не синхронизируются. Это означает, что он имеет лучшую производительность, чем последний, но недостатком является то, что он не является потокобезопасным.
Прочитайте учебник для более подробной информации.
StringBuilder намного быстрее, чем StringBuffer, потому что он не синхронизирован.
Здесь вы получили больше представление о стоимости синхронизации
Давайте посмотрим программно, насколько StringBuilder быстрее, чем StringBuffer
public class Test{
public static void main(String[] args){
long startTime = System.currentTimeMillis();
StringBuffer sb = new StringBuffer("Yasir");
for (int i=0; i<10000; i++){
sb.append("Shabbir");
}
System.out.println("Time taken by StringBuffer: " + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis();
StringBuilder sb2 = new StringBuilder("Yasir");
for (int i=0; i<10000; i++){
sb2.append("Shabbir");
}
System.out.println("Time taken by StringBuilder: " + (System.currentTimeMillis() - startTime) + "ms");
}
}
Выход
Время, затраченное StringBuffer: 16 мс
Время, затраченное StringBuilder: 0 мс
Простая программа, иллюстрирующая разницу между 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");
}
}
}
Лучше использовать StringBuilder, поскольку он не синхронизирован и, следовательно, обеспечивает лучшую производительность. StringBuilder является заменой старого StringBuffer.
String-Builder:
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);
По возможности рекомендуется использовать StringBuilder, потому что он работает быстрее, чем StringBuffer. Однако, если требуется безопасность потока, лучшим вариантом являются объекты StringBuffer.
StringBuffer:
- Многопотоковый
- синхронизированный
- Медленнее, чем StringBuilder
StringBuilder
- Однозаходные
- Не-Синхронное
- Быстрее, чем когда-либо String
String является неизменным объектом, что означает, что значение не может быть изменено, поскольку StringBuffer является изменяемым.
StringBuffer синхронизирован и, следовательно, безопасен для потоков, поскольку StringBuilder не подходит и подходит только для однопоточных экземпляров.
StringBuffer используется для хранения символьных строк, которые будут изменены (объекты String не могут быть изменены). Он автоматически расширяется по мере необходимости. Связанные классы: String, CharSequence.
StringBuilder был добавлен в Java 5. Он идентичен StringBuffer во всех отношениях, за исключением того, что он не синхронизирован, что означает, что если к нему одновременно обращаются несколько потоков, могут возникнуть проблемы. Для однопоточных программ, наиболее распространенный случай, позволяющий избежать накладных расходов на синхронизацию, делает StringBuilder немного быстрее.
StringBuffer
синхронизируется, но StringBuilder
не является. В следствии, StringBuilder
быстрее чем StringBuffer
,
StringBuffer является изменяемым. Это может измениться с точки зрения длины и содержания. StringBuffers являются поточно-ориентированными, что означает, что у них есть синхронизированные методы для контроля доступа, так что только один поток может одновременно получить доступ к синхронизированному коду объекта StringBuffer. Таким образом, объекты StringBuffer, как правило, безопасны для использования в многопоточной среде, где несколько потоков могут одновременно пытаться получить доступ к одному и тому же объекту StringBuffer.
StringBuilder Класс StringBuilder очень похож на StringBuffer, за исключением того, что его доступ не синхронизирован, поэтому он не является потокобезопасным. Без синхронизации производительность StringBuilder может быть лучше, чем StringBuffer. Таким образом, если вы работаете в однопоточной среде, использование StringBuilder вместо StringBuffer может привести к повышению производительности. Это также верно для других ситуаций, таких как локальная переменная StringBuilder (т. Е. Переменная в методе), где только один поток будет обращаться к объекту StringBuilder.
StringBuffer
StringBuffer является изменяемым, что означает, что можно изменить значение объекта. Объект, созданный с помощью StringBuffer, хранится в куче. StringBuffer имеет те же методы, что и StringBuilder, но каждый метод в StringBuffer синхронизирован, то есть StringBuffer является потокобезопасным.
StringBuilder
StringBuilder такой же, как StringBuffer, то есть он хранит объект в куче, и его также можно изменить. Основное различие между StringBuffer и StringBuilder заключается в том, что StringBuilder не является потокобезопасным. StringBuilder работает быстро, так как не является потокобезопасным.
Между StringBuilder и StringBuffer нет принципиальных отличий, между ними существует лишь несколько отличий. В StringBuffer методы синхронизируются. Это означает, что одновременно только один поток может работать с ними. Если существует более одного потока, то второй поток должен будет ждать завершения первого, а третий должен ждать окончания первого и второго и так далее. Это делает процесс очень медленным и, следовательно, производительность в случае StringBuffer низкая.
С другой стороны, StringBuilder не синхронизирован. Это означает, что одновременно несколько потоков могут работать с одним и тем же объектом StrinBuilder одновременно. Это делает процесс очень быстрым и, следовательно, производительность StringBuilder высока.
Поскольку StringBuffer
синхронизируется, это требует дополнительных усилий, поэтому, исходя из производительности, оно немного медленнее, чем StringBuilder
,
Основное отличие заключается в StringBuffer
синхронизирован, но StringBuilder
Если нет необходимости использовать более одного потока, то рекомендуется 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;
}
Так как приложение является synchronized
, StringBuffer
имеет производительность по сравнению с StrinbBuilder
в многопоточном сценарии. Пока вы не разделяете буфер между несколькими потоками, используйте StringBuilder
, что быстро из-за отсутствия synchronized
в методах добавления.