StringBuffer와 StringBuilder의 차이
String은 상수이기 때문에 String에 +를 사용하여 문자열을 이어붙이는 것은 매우 권장되지 않는 방법입니다.
그렇기 때문에 StringBuffer나 StringBuilder를 사용하여 문자열을 잇는 것이 대부분인데요.
StringBuffer와 StringBuilder. 서로 무슨 차이가 있을테니 서로 구분해서 사용할 것입니다.
이번에는 String으로 문자열 잇는 것이 왜 안 좋은가, 그리고 StringBuffer와 StringBuilder의 차이를 알아봅시다.
public class Difference { public static void main(String[] args) { String first = "a"; StringBuilder second = new StringBuilder("a"); StringBuffer third = new StringBuffer("a"); String temp = "a"; long start = System.nanoTime(); for(int i = 0; i < 1000; i++) first += temp; long end = System.nanoTime(); System.out.print("String::\t"); System.out.println(((end - start)/1000) + "ns"); start = System.nanoTime(); for(int i = 0; i < 1000; i++) third.append(temp); end = System.nanoTime(); System.out.print("StringBuffer::\t"); System.out.println(((end - start)/1000) + "ns"); System.out.println(third.capacity()); start = System.nanoTime(); for(int i = 0; i < 1000; i++) second.append(temp); end = System.nanoTime(); System.out.print("StringBuilder::\t"); System.out.println(((end - start)/1000) + "ns"); System.out.println(second.capacity()); System.out.println("결론:: StringBuilder >> StringBuffer >>>>> String"); } }
String으로 문자열을 이으면 안 좋은 이유는 위 소스코드 하나면 충분히 납득하실 수 있을 것 같습니다.
제 컴퓨터의 경우 위 소스를 실행시킨 결과 String: 4180ms, StringBuffer: 740ms, StringBuilder: 210ms가 걸렸습니다.
문자열을 한 두개 잇는 것은 지장이 없지만 많은 문자열을 이을 경우 메모리는 둘째치고 속도에서 엄청난 손해를 보게 되죠.
StringBuffer와 StringBuilder는 무슨 차이가 있을까요?
차이를 알기 위해서는 먼저 쓰레드라는 것을 알아야 합니다. (참고:: 쓰레드(extends Thread와 runnable))
StringBuffer는 쓰레드를 사용하며 Thread-safe입니다.
StringBuilder는 쓰레드를 사용하지 않으며 그러므로 non-Thread-safe입니다.
생각해보면 쓰레드를 이용하여 여러 명이 일을 하는 것이 더 빠를 것 같은데 오히려 더 느립니다.
그 이유는 쓰레드를 이용하여 빠르게 일을 처리하긴 하지만 다른 쓰레드를 기다리는 과정에서 지연이 일어나기 때문입니다.
그래서 오히려 쓰레드를 사용하지 않는 StringBuilder가 더 빠르게 문자열을 잇는 것입니다.
그렇다면 StringBuffer는 쓸모가 없는가.. 하면 그것도 아닙니다.
멀티쓰레드로 문자열을 이을 경우 StringBuffer는 빛을 발하는데 이는 Thread-safe라는 점을 주목해야 합니다.
멀티쓰레드일 때 StringBuilder는 문자열을 제대로 잇지 못합니다. 각각의 쓰레드가 따로따로 일하기 때문이죠.
그래서 멀티쓰레드를 사용할 때는 StringBuilder보다 안전한 StringBuffer를 쓰는 것이 아주 조금 느리더라도 좋습니다.
public class BufferVSBuilder { public static void main(String[] args) throws InterruptedException { int n = 2; StringBuilder sb = new StringBuilder(); StringBuilderTest[] builderThreads = new StringBuilderTest[n]; for(int i = 0 ; i < n; i++) builderThreads[i] = new StringBuilderTest(sb); for(int i = 0 ; i < n; i++) builderThreads[i].start(); for(int i = 0 ; i < n; i++) builderThreads[i].join(); System.out.println("StringBuilderTest: " + sb.length()); //************************************************************** StringBuffer sb2 = new StringBuffer(); StringBufferTest[] bufferThreads = new StringBufferTest[n]; for(int i = 0 ; i < n; i++) bufferThreads[i] = new StringBufferTest(sb2); for(int i = 0; i < n; i++) bufferThreads[i].start(); for(int i = 0 ; i < n; i++) bufferThreads[i].join(); System.out.println("StringBufferTest: " + sb2.length()); } } class StringBuilderTest extends Thread { StringBuilder sb; public StringBuilderTest(StringBuilder sb) { this.sb = sb; } public void run() { for(int i = 0; i < 100; i++) { sb.append("A"); } } } class StringBufferTest extends Thread { StringBuffer sb; public StringBufferTest(StringBuffer sb) { this.sb = sb; } public void run() { for(int i= 0 ; i < 100; i++) { sb.append("A"); } } }
멀티쓰레드를 사용할 때 StringBuilder와 StringBuffer 테스트 소스코드
+ StringBuilder에서 왜 equal() 메서드가 없는지 궁금해하시는 분이 계셨는데 StringBuilder는 그 자체가 String이 아닙니다.
StringBuilder는 String을 가지는 Builder입니다. 더 정확하게 알고 싶다면 디자인 패턴에 대해 공부하시면 됩니다.
StringBuilder에 넣은 문자열을 equal()을 사용하여 비교하고 싶다면 [변수].toString().equal()을 사용하시면 됩니다.
'자바 > 자바 - 짧게 쓰는 글' 카테고리의 다른 글
톰캣이 정상적으로 실행되지 않을 때(Tomcat failed to start) (0) | 2017.07.10 |
---|---|
String <-> byte[] 변환 방법 (0) | 2017.07.09 |
왜 저장이 안될까? close()는 매우 중요합니다! (0) | 2017.03.28 |
String을 저장하는 두 가지 방법과 String pool (3) | 2016.06.26 |
[자바] 인터페이스는 다중 상속이 되는 이유 (0) | 2016.05.18 |