Java를 사용해 알고리즘 문제를 풀다가, StringBuffer와 StringBuilder의 사용법도, 내장 메서드도 비슷한데 왜 두 가지로 나뉘어져 있는가에 대한 의문이 들었다. 그렇게 찾아보니 String과의 차이도 중요하다는 것을 알게 되었다.
이번 포스팅에서는 세 가지 자료형에 대한 성능과 차이를 공부한 것을 정리해보려 한다.
1. String 과 StringBuffer / StringBuilder 비교
String
우선 StringBuilder와 StringBuffer는 주로 문자열을 이어붙일 때 주로 사용한다. 하지만, String만으로도 concat() 또는 "+" 연산을 통해 문자열을 이어 붙일 수 있다.
굳이 String이 아닌 StringBuilder와 StringBuffer를 사용하는 이유가 무엇일까?
바로 String을 통해 문자열을 결합하게 되면, 공간의 낭비와 성능이 매우 느려지기 때문이다. 이유는 String 객체가 불변 자료형이기 때문이다.
실제 String 객체의 내부를 들여다보면, 아래처럼 value 변수가 final로 선언된 것을 볼 수 있다.
여기서 value 값이 인스턴스 생성시에 생성자의 매개변수로 입력받는 문자열이다. 이 value라는 변수가 final이기 때문에 값을 바꿀 수 없다.
그런데 String 객체에 concat() 또는 "+"를 이용해 값을 변환하는 것은 어떻게 가능할까?
이것은 값을 변환하는 것이 아니라, 새로운 값을 업데이트하는 것이기 때문에 가능하다.
문자열을 합치는 것 뿐만 아니라, String 의 값을 변환시키는 trim 등의 메서드는 문자열 자체를 변경하는 것이 아닌 새로운 String 객체를 생성해 업데이트한다.
그래서 String 은 문자열을 결합하면 결합할수록, 공간의 낭비 뿐 아니라 속도가 매우 느려지게 되는 단점이 있다.
StringBuffer / StringBuilder
반면 StringBuffer 와 StringBuilder는 가변적이다.
자바 코드를 열어보면 StringBuffer 와 StringBuilder는 모두 AbstractStringBuilder를 extends하는 것을 알 수 있다.
그리고 AbstractStringBuilder는 final 선언이 되어있지 않는 가변적인 구조라는 것을 알 수 있다.
두 클래스를 들여다보면 데이터를 임시로 저장하는 buffer를 통해 문자열을 저장하고, 그 안에서 문자열 변환 작업을 할 수 있도록 되어있다.
그렇기 때문에 String과는 달리, 문자열 연산시에 동일 객체 내에서 문자열이 변경될 수 있다.
그러므로, String에 비해 공간 낭비가 없고, 새로운 인스턴스를 만드는 String과 달리 속도가 빠르다는 강점이 있다.
String.concat(), StringBuffer, StringBuilder 성능 비교
그래서, String.concat() 과 StringBuffer, StringBuilder의 성능은 아래처럼 확연한 차이가 나는 것을 볼 수 있다.
2. 코드로 StringBuffer와 StringBuilder 비교해보기
StringBuffer와 StringBuilder 클래스는 둘 다 크기가 가변적으로 변하고, 제공하는 메서드도 동일하다. 한 가지 다른 것은 멀티 스레드 환경에서 안전한가, 안전하지 않은가이다.
결론부터 말하면 StringBuffer 클래스는 스레드에서 안전(thread safe)하고, StringBuilder 클래스는 스레드에서 안전하지 않다 (thread unsafe).
StringBuffer는 메서드에서 synchronized 키워드를 사용하기 때문에, 동기화를 지원해 멀티 스레드에서 안전하게 동작할 수 있다.
아래는 다른 포스팅에서 참고한 코드이다.
//출처 : https://inpa.tistory.com/entry/JAVA-String-StringBuffer-StringBuilder차이점성능비교
import java.util.*;
public class Main extends Thread{
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer();
StringBuilder stringBuilder = new StringBuilder();
new Thread(() -> {
for(int i=0; i<10000; i++) {
stringBuffer.append(1);
stringBuilder.append(1);
}
}).start();
new Thread(() -> {
for(int i=0; i<10000; i++) {
stringBuffer.append(1);
stringBuilder.append(1);
}
}).start();
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("StringBuffer.length: "+ stringBuffer.length()); // thread safe 함
System.out.println("StringBuilder.length: "+ stringBuilder.length()); // thread unsafe 함
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
출처: https://inpa.tistory.com/entry/JAVA-☕-String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨💻:티스토리]
StringBuffer.length: 20000
StringBuilder.length: 19628
출처: https://inpa.tistory.com/entry/JAVA-☕-String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨💻:티스토리]
두 개의 스레드가 있고 각 스레드는 배열 요소를 1만번 추가하게 되는 로직이다. 그러면 결과적으로 문자열 배열의 크기는 2만이 나와야 한다.
하지만, StringBuider의 결과 값은 2만번에 미치지 못하는 결과로, Thread Safe하지 못한 것을 볼 수 있다.
동기화를 제외한 단순 성능은 스레드와 관련된 연산이 없기 때문에 StringBuilder가 조금 더 빠르다. 하지만 멀티 스레드 환경에서는 StringBuffer로 사용하는 것이 안정적이다.
각각의 상황에 따라 정리를 하자면 다음과 같다.
String은 짧은 문자열을 더할 경우에 사용하고, 그 외에는 StringBuffer와 StringBuilder가 효율적이다.
그리고, StringBuilder는 스레드에 안전한지 여부가 전혀 관계 없는 서비스를 개발할 때가 적절하다
StringBuffer는 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우에 효율적이다.
참고 자료
String-StringBuffer-StringBuilder-차이점-성능-비교 [Inpa Dev 👨💻:티스토리]
https://inpa.tistory.com/entry/JAVA-%E2%98%95-String-StringBuffer-StringBuilder-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90
Java-StringBuffer와-StringBuilder의-차이
https://velog.io/@p_zane/Java-StringBuffer%EC%99%80-StringBuilder%EC%9D%98-%EC%B0%A8%EC%9D%B4
[자바] String, StringBuilder, StringBuffer의 차이 [길은 가면, 뒤에 있다.:티스토리]
https://12bme.tistory.com/42
'Java > Java 를 파헤쳐보자' 카테고리의 다른 글
[Java 파헤쳐보기] Vector vs ArrayList (0) | 2024.04.11 |
---|---|
[Java 파헤쳐보기] JCF 소개 (1) | 2024.04.11 |
[Java 파헤쳐보기] Java의 가비지 컬렉터(Garbage Collector) (0) | 2023.12.16 |
[Java 파헤쳐보기] Java의 바이트 코드 눈으로 확인해보기 (0) | 2023.12.08 |
[Java 파헤쳐보기] JVM을 파헤쳐보자 (0) | 2023.12.01 |