String,StringBuffer,StringBuilder

greenTea·2023년 11월 9일
0

String,StringBuffer,StringBuilder

String

🤔String 객체는 불변입니다. 한 번 생성된 String의 값은 변경할 수 없으며, 문자열을 조작할 때마다 새로운 String 객체가 생성됩니다.

String str = "Hello";
str += " World"; // 이 시점에서 새로운 String 객체가 생성됩니다.
System.out.println(str); // 출력: Hello World

장점:

  • 불변성으로 인해 쓰레드 안전(thread-safe).
  • 문자열 리터럴은 상수 풀에 저장되므로 메모리를 효율적으로 사용할 수 있음.

단점:

  • 문자열 연결이나 변경 작업이 많을 경우 메모리 낭비가 심하고 성능이 저하될 수 있음.

StringBuffer

😎StringBuffer는 가변적이고, 동기화되어 있어 멀티스레드 환경에서 안전합니다.

StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World"); // 기존 객체에 문자열을 추가합니다.
System.out.println(buffer.toString()); // 출력: Hello World

장점:

  • 멀티스레드 환경에서 안전하게 사용할 수 있음.
  • 문자열 조작 시 새로운 객체 생성 없이 내용을 변경할 수 있음.

단점:

  • 단일 스레드 환경에서는 StringBuilder보다 성능이 떨어짐.

StringBuilder

😑StringBuilderStringBuffer와 유사하지만 동기화를 지원하지 않아 단일 스레드 환경에서 더 빠른 성능을 제공합니다.

StringBuilder builder = new StringBuilder("Hello");
builder.append(" World"); // 기존 객체에 문자열을 추가합니다.
System.out.println(builder.toString()); // 출력: Hello World

장점:

  • 단일 스레드 환경에서 StringBuffer에 비해 빠른 성능을 제공.
  • 문자열 조작 시 새로운 객체 생성 없이 내용을 변경할 수 있음.

단점:

  • 멀티스레드 환경에서는 쓰레드 안전하지 않음.

StringBuilder vs StringBuffer

🫠둘다 비슷한 기능을 하지만 결정적으로 스레드 안전에 따라 갈립니다.
아래 코드를 실행해보면...

코드

public class MyTest {

    @Test
    void t1() {
        StringBuilder sbi = new StringBuilder();
        Runnable r = () -> {
            for (int i = 0; i < 30000; i++) {
                sbi.append("a");
            }
        };

        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);

        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("StringBuilder: "+sbi.length());

    }

    @Test
    void t2() {
        StringBuffer sbf = new StringBuffer();

        Runnable r = () -> {
            for (int i = 0; i < 30000; i++) {
                sbf.append("a");
            }
        };

        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);

        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("StringBuffer: "+sbf.length());
    }
}

스레드를 2개 생성해서 각각 for문을 30000번 돌립니다.
만약 스레드 안전하다면 2번의 for문을 돌았기에 60000이 나와야 합니다.
실제 결과를 보면...

결과

StringBuilder: 40812
StringBuffer: 60000

정리

☺️StringBufferStringBuilder는 사용 방법이 거의 동일하지만, StringBuffer는 내부적으로 동기화를 제공하여 멀티스레드 환경에서 안전하다는 차이가 있습니다.

StringBuffer의 내부구현

synchronized가 달려있는 모습을 확인 할 수 있습니다.


반면, StringBuilder는 동기화 오버헤드가 없어 단일 스레드에서 더 효율적입니다. 따라서 작업의 스레드 안전성 요구 사항에 따라 적절한 클래스를 선택해야 합니다.

🫡웬만하면 StringBuffer를 쓰는 것이 좋을 것 같습니다

profile
greenTea입니다.

0개의 댓글