String
, StringBuilder
, 그리고 StringBuffer
는 Java에서 문자열을 다루기 위한 클래스
🥕 String
- 불변성 (Immutability)
String
은 불변하는 문자열을 나타낸다.
String
객체에 저장된 문자열은 생성된 후에 변경할 수 없다.
- 문자열을 수정하는 것처럼 보이는 모든 작업은 사실상 새로운
String
객체를 생성한다.
- 효율성
- 불변성 때문에
String
은 문자열 연산이 많은 경우 비효율적일 수 있다.
- 예를 들어, 반복적인 문자열 연결은 매번 새로운
String
객체를 생성하기 때문에 메모리 사용과 성능에 부담을 줄 수 있다.
- 메모리 공간의 낭비가 발생하고 성능이 떨어진다.
- 보안과 스레드 안전
- 불변성은
String
을 스레드 안전(thread-safe)하게 만듭니다.
- 또한, 보안 관련 코드에서 중요한 정보(예: 비밀번호)를 다룰 때 변경 불가능하다는 점이 유리할 수 있다.
- JDK 1.5 이후부터는 컴파일 타임에 StringBuilder로 변경한다고 한다.
- 불변 객체이기 때문에 멀티 쓰레드 환경에서 동기화를 신경쓰지 않아도 된다.
- 문자열 연산이 적고, 조회가 많은 상황에서 쓰기 좋다.
🥕 StringBuilder, StringBuffer
StringBuilder
- 가변성 (Mutability)
StringBuilder
는 가변적인 문자열을 나타낸다.
- 이 클래스를 사용하면 기존의 문자열 내용을 변경하거나 추가할 수 있어, 반복적인 문자열 수정 작업에서 높은 성능을 제공
- 스레드 안전하지 않음
StringBuilder
는 스레드 안전하지 않다.
- 따라서 멀티 스레드 환경에서는 주의해서 사용해야 한다
- 성능:
StringBuilder
는 String
보다 문자열 연산(추가, 수정, 삭제 등)에 있어 훨씬 효율적
- StringBuilder는 동기화를 고려하지 않는 상황에서 사용.(Thread를 사용하지 않는 상황.) 문자열 연산이 많은 싱글 쓰레드 환경.
StringBuffer
- 가변성 (Mutability): StringBuffer도 StringBuilder와 마찬가지로 가변적인 문자열을 다룹니다. StringBuilder와 비슷한 API를 제공
- 스레드 안전 (Thread-Safe)
- StringBuffer의 주요 차이점은 스레드 안전하게 설계되었다는 것
- 이는 StringBuffer의 모든 주요 연산이
동기화(synchronized)
되어 있다는 의미
- 성능
- StringBuffer는 StringBuilder에 비해 느릴 수 있다.
- 이는 동기화로 인한 오버헤드 때문이다. 따라서 단일 스레드 환경에서는 StringBuilder가 선호
- StringBuffer는 동기화가 필요한 멀티 쓰레드 환경에서 사용. 문자열 연산이 많은 멀티 쓰레드 환경.
공통점
- String과 다르게 Mutable한 객체이다.
- 따라서 문자열 연산 시 새롭게 객체를 생성하지 않고, 처음에 만든 객체를 이용해 연산하고 크기를 변경시켜 문자열을 변경한다.
- 따라서 문자열 연산이 자주 발생하는 상황에서 성능적으로 유리하며 쓰기 좋다.
차이점
- StringBuilder : Thread-Safe 하지 않다. 멀티 쓰레드 지원하지 않음.
- StringBuffer : Thread-Safe 하다. 멀티 쓰레드 지원함.
- 즉, 동기화 지원의 유무.
🥕 스레드
멀티태스킹의 해결책 : 스레드(thread)의 특징
- 프로세스는 한 개 이상의 스레드 가질 수 있다.
- 한 프로세스 안에서 여러 개의 작업을 동시에 실행하기 위해 이 여러 개의 하나하나를 맡아 줄 것이 필요한데 그것이 스레드
- CPU에서 실행되는 단위(unit of execution)
- 예전에는 프로세스가 cpu에서 실행되는 단위였다면… 지금은 스레드가 cpu가 실행되는 단위
같은 프로세스의 스레드들끼리
컨텍스트 스위칭은 가볍다.
- 스레드들은 자신들이 속한 프로세스의 메모리 영역을 공유
- 그렇기 때문에 3번인 컨텍스트 스위칭이 가볍고
- 두 번째로는 같은 프로세스 안의 스레드들끼리는 데이터 공유가 쉽다.
메모리 구조 비교(싱글 스레드 vs 멀티 스레드)
💡 파란색과 녹색은 스레드들이 속한 메모리 영역
싱글 스레드
- 싱글 스레드를 가지는 프로세스
- 스레드가 나오기 전에 프로세스만의 메모리 구조
멀티 스레드
같은 프로세스를 가진 스레드들은 같은 메모리 공간을 공유하되, 스레드들 만의 고유한 영역도 있다.
- 스레드가 등장하고 난 뒤 메모리 구조
힙 메모리 영역
을 공유
- 자신의 고유한 영역이 바로
스택
- 각각의 스레드마다 프로그램 카운터들이 따로 있음
- 프로그램 카운터 : 다음번에 실행돼야 할 명령어가 있는 메모리 주소를 가짐
스레드 예시
- cpu인데 코어가 2개인 cpu는 병렬적으로 스레드가 실행
🥕 멀티스레딩
개념
- 위에서 예시든 코어가 두 개일 때 동작하는 방식
- 하나의 프로세스가 동시에 여러 작업[스레드]을 실행하는데 목적
확장된 멀티태스킹 개념
- 여러 프로세스와 여러 스레드가 아주 짧게 쪼개진 cpu time을 나눠 갖는 것
동기화(Synchronization)
여러 스레드가 동시에 같은 자원(예: 데이터, 객체)에 접근할 때 발생할 수 있는 충돌이나 데이터 무결성 문제를 방지하기 위한 메커니즘으로 동기화는 공유 자원에 대한 동시 접근을 제어하여, 한 시점에 하나의 스레드만이 해당 자원을 사용할 수 있게 함
으로써 일관성과 안정성을 유지
동기화의 필요성
- 데이터 무결성 보장: 여러 스레드가 동시에 데이터를 수정하려 할 때, 동기화 없이는 예측 불가능한 결과나 데이터 손상이 발생할 수 있다.
- 경쟁 상태(또는 경합 조건) 방지: 두 개 이상의 스레드가 동시에 공유 자원을 접근하려고 할 때 발생하는 문제를 방지합
- 일관성 유지: 동기화를 통해 프로그램의 일관된 동작을 보장한다.
동기화의 구현 방법
- 락(Lock): 공유 자원에 접근하기 전에 락을 획득하고, 접근이 끝난 후에 락을 해제한다. 이를 통해 해당 자원을 사용하는 동안 다른 스레드의 접근을 막는다.
- 세마포어(Semaphore): 한정된 수의 스레드만이 동시에 자원에 접근할 수 있도록 허용하는 데 사용
- 모니터(Monitor): 객체에 대한 동기화된 접근을 제공합니다. Java에서는
synchronized
키워드를 사용하여 메서드나 블록을 동기화할 수 있습니다.
Java에서의 동기화
Java에서 동기화는 주로 synchronized
키워드를 통해 이루어진다. synchronized
메서드나 블록은 한 스레드가 실행을 완료하기 전까지 다른 스레드가 해당 메서드나 블록에 접근하는 것을 막는다.
javaCopy code
public synchronized void synchronizedMethod() {
}
또는 특정 객체에 대한 락을 사용하는 동기화 블록을 사용할 수도 있다:
javaCopy code
public void method() {
synchronized (this) {
}
}