728x90

SimpleDateFormat은 내부적으로 공유 상태(Shared State)를 가지기 때문에 멀티스레드 환경에서 동시 접근 시 데이터 충돌이 발생할 수 있음.
🔥 문제 상황 예제 (멀티스레드 환경에서 발생하는 오류)
다음은 여러 스레드에서 동시에 SimpleDateFormat을 공유할 경우 발생할 수 있는 문제를 보여줍니다.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleDateFormatExample {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
String formattedDate = sdf.format(new Date());
System.out.println(Thread.currentThread().getName() + " - " + formattedDate);
});
}
executorService.shutdown();
}
}
✅ 예상 출력 (정상적으로 보일 수도 있음)
pool-1-thread-1 - 2025-02-19 16:30:01
pool-1-thread-2 - 2025-02-19 16:30:01
...
❌ 문제점:
멀티스레드 환경에서 SimpleDateFormat이 공유되면 내부적으로 같은 Date 객체를 참조하여 엉뚱한 결과가 출력되거나 ParseException, NumberFormatException 같은 오류가 발생할 수 있음.
✅ 해결 방법 1: ThreadLocal 사용 (스레드별 인스턴스 생성)
각 스레드가 자신만의 SimpleDateFormat 인스턴스를 가지도록 ThreadLocal을 사용하면 문제를 방지할 수 있음.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadLocalExample {
private static final ThreadLocal<SimpleDateFormat> threadLocalSdf =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
SimpleDateFormat sdf = threadLocalSdf.get(); // 각 스레드별 독립된 인스턴스
String formattedDate = sdf.format(new Date());
System.out.println(Thread.currentThread().getName() + " - " + formattedDate);
});
}
executorService.shutdown();
}
}
✅ 출력 예시 (안정적으로 동작함)
pool-1-thread-1 - 2025-02-19 16:35:10
pool-1-thread-2 - 2025-02-19 16:35:10
...
✔️ ThreadLocal을 사용하면 각 스레드마다 독립된 SimpleDateFormat 인스턴스를 보장하기 때문에 스레드 충돌이 발생하지 않음.
✅ 해결 방법 2: DateTimeFormatter (Java 8 이상)
Java 8 이상이라면 DateTimeFormatter를 사용하는 것이 최선입니다.
이 클래스는 불변(Immutable)하고 Thread-Safe하게 설계됨.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DateTimeFormatterExample {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
String formattedDate = LocalDateTime.now().format(formatter);
System.out.println(Thread.currentThread().getName() + " - " + formattedDate);
});
}
executorService.shutdown();
}
}
✅ 출력 예시 (Thread-Safe)
pool-1-thread-1 - 2025-02-19 16:40:30
pool-1-thread-2 - 2025-02-19 16:40:30
...
✔️ Java 8 이상이라면 DateTimeFormatter를 사용하여 ThreadLocal 없이 안전하게 날짜를 포맷할 수 있음.
🔥 정리
| 방법 | Thread-Safe 여부 | 장점 | 단점 |
| SimpleDateFormat 공유 | ❌ | 간단한 코드 | 멀티스레드 환경에서 충돌 발생 가능 |
| ThreadLocal<SimpleDateFormat> | ✅ | Java 7 이하에서도 Thread-Safe | 코드가 다소 복잡 |
| DateTimeFormatter (Java 8 이상) | ✅ | 간결하고 Thread-Safe | Java 8 이상에서만 사용 가능 |
🔷 추천
- Java 8 이상이면 DateTimeFormatter 사용 (✅ 가장 권장)
- Java 7 이하에서는 ThreadLocal<SimpleDateFormat> 사용
즉, Java 7 이하에서는 ThreadLocal을 활용해 스레드별 독립된 SimpleDateFormat 인스턴스를 유지하는 것이 가장 안전한 방법입니다.
728x90
'개발 > 자바' 카테고리의 다른 글
| Java 5 가변 매개변수 (Varargs) (0) | 2025.02.19 |
|---|---|
| LocalDate 주요 메서드 정리 (0) | 2025.02.19 |
| Java 7 이하에서 날짜 및 시간 관련 클래스 (0) | 2025.02.19 |
| Java8 : LocalDate vs ZonedDateTime 차이 (0) | 2025.02.19 |
| Java8 : LocalDate, LocalTime, LocalDateTime 날짜 및 시간 관련 클래스 (0) | 2025.02.19 |