Разница между StringBuilder и StringBuffer - PullRequest
1462 голосов
/ 10 декабря 2008

В чем основная разница между StringBuffer и StringBuilder? Есть ли проблемы с производительностью при выборе любого из них?

Ответы [ 30 ]

1567 голосов
/ 10 декабря 2008

StringBuffer синхронизировано, StringBuilder нет.

702 голосов
/ 05 мая 2010

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);
        }
    }
}

A тестовый прогон дает числа 2241 ms для StringBuffer против 753 ms для StringBuilder.

235 голосов
/ 10 декабря 2008

Как правило, StringBuffer методы синхронизируются, а StringBuilder - нет.

Операции "почти" одинаковы, но использование синхронизированных методов в одном потоке является излишним.

Это довольно много об этом.

Цитата из StringBuilder API :

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

Так что это было сделано, чтобы заменить его.

То же самое произошло с Vector и ArrayList.

160 голосов
/ 25 января 2011

Но нужно было получить четкую разницу с помощью примера?

StringBuffer или StringBuilder

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

StringBuffer пришел первым. Sun заботилась о корректности при любых условиях, поэтому они сделали ее синхронизированной, чтобы на всякий случай сделать ее поточно-ориентированной.

StringBuilder пришли позже. Большинство использований StringBuffer были однопоточными и без необходимости платили за синхронизацию.

Поскольку StringBuilder представляет собой замену для StringBuffer без синхронизации, между примерами не будет различий.

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

76 голосов
/ 11 декабря 2013

Сначала давайте рассмотрим сходство : И StringBuilder, и StringBuffer являются изменяемыми. Это означает, что вы можете изменить их содержание, находясь в одном месте.

Отличия : StringBuffer также изменчив и синхронизирован. Где StringBuilder изменчив, но по умолчанию не синхронизируется.

Значение синхронизировано (синхронизация) : Когда что-то синхронизируется, то несколько потоков могут получить к нему доступ и изменить его без каких-либо проблем или побочных эффектов. StringBuffer синхронизирован, поэтому вы можете использовать его с несколькими потоками без каких-либо проблем.

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

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

49 голосов
/ 15 ноября 2012

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

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

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

41 голосов
/ 10 декабря 2008

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

Из Javadocs :

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

35 голосов
/ 12 апреля 2014

Довольно Хороший Вопрос

Вот различия, которые я заметил:

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.

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

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

22 голосов
/ 10 декабря 2008

StringBuilder не является потокобезопасным. String Buffer есть. Подробнее здесь .

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

21 голосов
/ 03 декабря 2010

StringBuilder и StringBuffer почти одинаковы. Разница в том, что StringBuffer синхронизирован, а StringBuilder нет. Хотя StringBuilder быстрее, чем StringBuffer, разница в производительности очень мала. StringBuilder является заменой СОЛНЦА StringBuffer. Это просто избегает синхронизации от всех открытых методов. Вместо этого их функциональность одинакова.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...