[java] StringBuilder와 StringBuffer의 차이점

사이의 주요 차이점은 무엇입니까 StringBuffer와는 StringBuilder? 이들 중 하나를 결정할 때 성능 문제가 있습니까?



답변

StringBuffer동기화 StringBuilder되지 않습니다.


답변

StringBuilderStringBuffer그렇지 않기 때문에 보다 빠릅니다.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하기위한 StringBuffer753 ms를위한 StringBuilder.


답변

기본적으로 StringBuffer메소드는 동기화 StringBuilder되지 않은 상태에서 동기화 됩니다.

작업은 “거의”동일하지만 단일 스레드에서 동기화 된 메소드를 사용하는 것은 과도합니다.

그것은 거의 그것에 관한 것입니다.

StringBuilder API 에서 인용 :

이 클래스 [StringBuilder]는 StringBuffer와 호환되는 API를 제공 하지만 동기화를 보장하지는 않습니다 . 이 클래스는 문자열 버퍼가 단일 스레드에 의해 사용되는 장소에서 StringBuffer를 대체하는 대체물로 사용하도록 설계되었습니다 (일반적인 경우). 가능한 경우이 클래스 는 대부분의 구현에서 더 빠를 것이기 때문에 StringBuffer 보다 우선적으로 사용하는 것이 좋습니다 .

그래서 그것을 대체하기 위해 만들어졌습니다.

동일은 무슨 일이 있었 Vector하고 ArrayList.


답변

그러나 예제의 도움으로 명확한 차이를 얻어야합니까?

StringBuffer 또는 StringBuilder

StringBuilder스레드간에 버퍼를 실제로 공유하지 않는 한 간단하게 사용하십시오 . StringBuilder원래 동기화 StringBuffer클래스 의 동기화되지 않은 (더 적은 오버 헤드 = 더 효율적인) 남동생 입니다.

StringBuffer먼저왔다. Sun은 모든 조건에서 정확성에 관심을 가졌기 때문에 만일의 경우를 대비하여 스레드 안전을 위해 동기화했습니다.

StringBuilder나중에왔다. 대부분의 용도 StringBuffer는 단일 스레드이며 불필요하게 동기화 비용을 지불했습니다.

이후 StringBuilderA는 드롭 인 교체 용은StringBuffer 동기가없는 모든 실시 예 사이의 차이가 없을 것이다.

당신이하면 되는 스레드간에 공유에 노력하고, 당신이 사용할 수있는 StringBuffer, 그러나 아마 대신 StringBuffer를 사용의 예를 들면, 높은 레벨의 동기화가 필요한지 여부를 고려, 당신은 모두 StringBuilder를 사용하는 방법을 동기화해야합니다.


답변

먼저 유사점을 살펴 보겠습니다. StringBuilder와 StringBuffer는 모두 변경 가능합니다. 즉, 동일한 위치에서 컨텐츠를 변경할 수 있습니다.

차이점 : StringBuffer도 변경 가능하고 동기화됩니다. StringBuilder는 변경 가능하지만 기본적으로 동기화되지 않습니다.

동기화의 의미 (동기화) : 어떤 것이 동기화되면 여러 스레드가 액세스하여 문제 또는 부작용없이 스레드를 수정할 수 있습니다. StringBuffer는 동기화되어 있으므로 아무 문제없이 여러 스레드에서 사용할 수 있습니다.

언제 어느 것을 사용해야합니까?
StringBuilder : 수정할 수있는 문자열이 필요한 경우 하나의 스레드 만 액세스하고 수정합니다. StringBuffer : 수정이 가능한 문자열이 필요하고 여러 스레드가 액세스하고 수정하는 경우.

참고 : 불필요하게 StringBuffer를 사용하지 마십시오. 즉, 하나의 스레드 만 수정하고 액세스하는 경우 동기화에 대한 잠금 및 잠금 해제 코드가 많아 CPU 시간이 불필요하게 걸리므로 사용하지 마십시오. 필요한 경우가 아니면 잠금을 사용하지 마십시오.


답변

단일 스레드에서 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!

따라서 빌더는 버퍼보다 ​​빠르며 문자열 연결보다 빠릅니다. 이제 여러 스레드에 대해 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 개 추가하십시오. 동일한 테스트는 아니지만 이전 37ms와 비교하여 멀티 스레딩 사용시 StringBuffers 추가가 더 느리다고 가정 할 수 있습니다 . 그 이유는 JIT / hotspot / compiler / something이 잠금을 확인할 필요 가 없음을 감지하면 최적화하기 때문입니다 .

그러나 StringBuilder를 사용하면 java.lang.ArrayIndexOutOfBoundsException이 발생 합니다. 동시 스레드는 원하지 않는 곳에 무언가를 추가하려고 시도하기 때문입니다.

결론은 StringBuffer를 쫓아 갈 필요가 없다는 것입니다. 그리고 스레드가있는 곳에서 몇 나노 초를 얻기 전에 그들이 무엇을하고 있는지 생각하십시오.


답변

StringBuilder는 Java 1.5에서 도입되었으므로 이전 JVM에서는 작동하지 않습니다.

로부터 Javadoc과 :

StringBuilder 클래스는 StringBuffer와 호환되는 API를 제공하지만 동기화를 보장하지는 않습니다. 이 클래스는 문자열 버퍼가 단일 스레드에 의해 사용되는 장소에서 StringBuffer의 드롭 인 대체로 사용하도록 설계되었습니다 (일반적인 경우). 가능한 경우,이 클래스는 대부분의 구현에서 더 빠를 것이기 때문에 StringBuffer에 우선하여 사용하는 것이 좋습니다.