Вопрос

В чем основная разница между 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);
        }
    }
}

А тестовый забег дает номера 2241 ms для StringBuffer против 753 ms для StringBuilder.

По сути, StringBuffer методы синхронизируются, пока 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 синхронизирован, поэтому вы можете без проблем использовать его с несколькими потоками.

Какой из них использовать, когда?Строковый Строитель:Когда вам нужна строка, которую можно изменить, и только один поток обращается к ней и изменяет ее.Строковыйбуфер:Когда вам нужна строка, которую можно изменить, и несколько потоков обращаются к ней и изменяют ее.

Примечание :Не используйте 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 !

Таким образом, построители работают быстрее, чем буферы, и НАМНОГО быстрее, чем конкатенация строк.Теперь давайте воспользуемся Исполнитель для нескольких потоков:

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/горячая точка/компилятор/что-то выполняет оптимизацию, когда обнаруживает, что существует нет необходимость проверки замков.

Но с StringBuilder у вас есть java.lang.ArrayIndexOutOfBoundsException, потому что параллельный поток пытается добавить что-то туда, куда не следует.

Вывод: вам не нужно гоняться за StringBuffers.А там, где есть потоки, подумайте, что они делают, прежде чем пытаться выиграть несколько наносекунд.

StringBuilder был представлен в Java 1.5, поэтому он не будет работать с более ранними JVM.

Из Javaдокументация:

Класс StringBuilder предоставляет 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 is not synchronized 
 StringBuilder is not thread-safe
 StringBuilder performance is better than StringBuffer.

Обычное дело :-

Оба имеют одинаковые методы с одинаковыми сигнатурами.Оба изменчивы.

StringBuilder не является потокобезопасным.Строковый буфер есть.Больше информации здесь.

РЕДАКТИРОВАТЬ:Что касается производительности, то после горячая точка начинается, StringBuilder становится победителем.Однако для небольших итераций разница в производительности незначительна.

StringBuilder и StringBuffer почти одинаковы.Разница в том, что StringBuffer синхронизирован и StringBuilder не является.Хотя, StringBuilder быстрее, чем StringBuffer, разница в производительности очень небольшая. StringBuilder является заменой SUN StringBuffer.Он просто позволяет избежать синхронизации всех общедоступных методов.Более того, их функциональность одинакова.

Пример хорошего использования:

Если ваш текст будет меняться и будет использоваться несколькими потоками, то лучше использовать StringBuffer.Если ваш текст будет изменен, но используется одним потоком, используйте StringBuilder.

StringBuffer

  • Синхронизировано, следовательно, потокобезопасно
  • Потокобезопасный, следовательно, медленный

StringBuilder

  • Представлено в Java 5.0
  • Асинхронный, следовательно, быстрый и эффективный
  • Пользователю явно необходимо синхронизировать его, если он хочет.
  • Вы можете заменить его на 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 аналогичен 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

enter image description here

Ресурс: Строка против StringBuffer против StringBuilder

String является неизменным.

StringBuffer является изменяемым и синхронизированным.

StringBuilder также изменчив, но не синхронизирован.

А Javadoc объясняет разницу:

Этот класс предоставляет API, совместимый со StringBuffer, но без гарантии синхронизации.Этот класс предназначен для использования в качестве замены StringBuffer в тех местах, где строковый буфер использовался одним потоком (как это обычно бывает).По возможности рекомендуется использовать этот класс вместо StringBuffer, поскольку в большинстве реализаций он будет работать быстрее.

StringBuilder (представленный в Java 5) идентичен 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");
        }

    }
}

Лучше использовать StringBuilder, поскольку он не синхронизируется и, следовательно, повышает производительность.StringBuilder — это замена старого StringBuffer.

StringBuffer синхронизировано, но StringBuilder не является.Как результат, StringBuilder быстрее, чем StringBuffer.

СтрокаБуферявляется изменчивым.Он может меняться по продолжительности и содержанию.StringBuffers являются потокобезопасными, что означает, что они имеют синхронизированные методы для управления доступом, поэтому только один поток может одновременно получить доступ к синхронизированному коду объекта StringBuffer.Таким образом, объекты StringBuffer, как правило, безопасно использовать в многопоточной среде, где несколько потоков могут одновременно пытаться получить доступ к одному и тому же объекту StringBuffer.

Строитель строкКласс StringBuilder очень похож на StringBuffer, за исключением того, что доступ к нему не синхронизирован, поэтому он не является потокобезопасным.Без синхронизации производительность StringBuilder может быть выше, чем у StringBuffer.Таким образом, если вы работаете в однопоточной среде, использование StringBuilder вместо StringBuffer может привести к повышению производительности.Это также верно и для других ситуаций, таких как локальная переменная StringBuilder (т. е. переменная внутри метода), когда только один поток будет обращаться к объекту StringBuilder.

Строковыйбуфер:

  • Многопотоковый
  • Синхронизировано
  • Медленнее, чем 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);  

По возможности рекомендуется использовать StringBuilder, поскольку он быстрее, чем StringBuffer.Однако, если необходима потокобезопасность, лучшим вариантом являются объекты StringBuffer.

StringBuffer используется для хранения строк символов, которые будут изменены (объекты String не могут быть изменены).Он автоматически расширяется по мере необходимости.Связанные классы:Строка, СимвольнаяПоследовательность.

StringBuilder был добавлен в Java 5.Он во всех отношениях идентичен StringBuffer, за исключением того, что он не синхронизирован, а это означает, что если к нему одновременно обращаются несколько потоков, могут возникнуть проблемы.Для однопоточных программ (в наиболее распространенном случае) избегание накладных расходов на синхронизацию делает StringBuilder немного быстрее.

Между StringBuilder и StringBuffer нет принципиальных различий, между ними существует лишь несколько различий.В StringBuffer методы синхронизированы.Это означает, что одновременно с ними может работать только один поток.Если существует более одного потока, то второму потоку придется дождаться завершения первого, а третьему придется дождаться завершения первого и второго и так далее.Это делает процесс очень медленным и, следовательно, производительность в случае StringBuffer низкая.

С другой стороны, StringBuilder не синхронизирован.Это означает, что несколько потоков могут одновременно работать с одним и тем же объектом StrinBuilder.Это делает процесс очень быстрым и, следовательно, производительность StringBuilder высока.

С StringBuffer синхронизирован, требует дополнительных усилий, поэтому, исходя из производительности, он немного медленнее, чем StringBuilder.

String — это неизменяемый объект, что означает, что значение не может быть изменено, поскольку StringBuffer является изменяемым.

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 в методах добавления.

Вот результат тестирования производительности для Строка против 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");

  }

Казни меня в идее

Результат:

100000 итераций для добавления одного текста

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 не является потокобезопасным.
  • StringBuilder быстрее, чем StringBuffer.
  • StringBuffer синхронизируется, тогда как StringBuilder не синхронизирован.

Каждый метод, присутствующий в StringBuffer, синхронизирован.следовательно, одновременно только одному потоку разрешено работать с объектом StringBuffer.Это увеличивает время ожидания потока и создает проблемы с производительностью, чтобы преодолеть эту проблему Sun People Intodized StringBuilder в 1,5 версии.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top