🤔String
객체는 불변입니다. 한 번 생성된 String
의 값은 변경할 수 없으며, 문자열을 조작할 때마다 새로운 String
객체가 생성됩니다.
String str = "Hello"; str += " World"; // 이 시점에서 새로운 String 객체가 생성됩니다. System.out.println(str); // 출력: Hello World
장점:
단점:
😎StringBuffer
는 가변적이고, 동기화되어 있어 멀티스레드 환경에서 안전합니다.
StringBuffer buffer = new StringBuffer("Hello"); buffer.append(" World"); // 기존 객체에 문자열을 추가합니다. System.out.println(buffer.toString()); // 출력: Hello World
장점:
단점:
StringBuilder
보다 성능이 떨어짐.😑StringBuilder
는 StringBuffer
와 유사하지만 동기화를 지원하지 않아 단일 스레드 환경에서 더 빠른 성능을 제공합니다.
StringBuilder builder = new StringBuilder("Hello"); builder.append(" World"); // 기존 객체에 문자열을 추가합니다. System.out.println(builder.toString()); // 출력: Hello World
장점:
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
☺️StringBuffer
와 StringBuilder
는 사용 방법이 거의 동일하지만, StringBuffer
는 내부적으로 동기화를 제공하여 멀티스레드 환경에서 안전하다는 차이가 있습니다.
synchronized가 달려있는 모습을 확인 할 수 있습니다.
반면, StringBuilder
는 동기화 오버헤드가 없어 단일 스레드에서 더 효율적입니다. 따라서 작업의 스레드 안전성 요구 사항에 따라 적절한 클래스를 선택해야 합니다.
🫡웬만하면 StringBuffer를 쓰는 것이 좋을 것 같습니다