설명
SonarQube를 이용해 코드의 취약점이나 잠재적 오류 발생 포인트를 확인하고 있는도중에 아래와 같은 오류 메시지를 발견하였습니다.
이전에 작업하셨던 분이 String값을 Date 객체로 변환하기 위해 SimpleDateFormat을 쓰고,
모든 객체에서 참조하면 관리가 편해지고, 객체 생성을 안해도 되니까 static final을 이용해 만드신거 같습니다.
- 다행이 사용되는 부분이 없었습니다.
SonarQube에서는 저렇게 코드를 작성하는게 문제가 있다고 하는데 어떤문제가 있는지 한번 알아보도록 하겠습니다.
해당 에러의 구체적인 설명은 아래와 같이 나와있는데요
가장 윗줄에 Non-thread-safe fields should not be static
라고 적혀 있네요.
스레드에서 안전하지 않은 필드로 static이 되면 안된다. 라는 말 같은데요 아래 설명을 더 읽어보면
1 | 자바 라이브러리의 모든 클래스는 thread-safe 하게 작성되지 않았습니다. 멀티 스레드 방식으로 이것들을 사용하면 런타임에서 exception 또는 데이터 문제를 야기할 가능성이 높습니다. |
이런 설명과 함께 예제 코드까지 보여주고 있습니다.
결국 SimpleDateFormat을 멀티 스레드 환경에서 사용시에는 static 키워드를 사용하면 안된다고 하는건데 왜 쓰면 문제가 날지 궁금해졌습니다.
일단 SimpleDateFormat 클래에도 아래와 같은 설명이 있었습니다.
1 | /* |
테스트
그럼 SimpleDateFormat을 멀티 스레드에서 사용했을때 어떤 문제가 발생하는지 한번 테스트를 해 보도록 하겠습니다.
SimpleDateFormat을 static으로 만들어주고
1 | public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); |
스레드 안에서 String으로 입력된 날짜를 파싱하는 그런 형태로 테스트를 진행을 해보았는데요
1 | String date = "20210819"; |
아래와같은 형태의 NumberFormatException 이 발생을 하였고
1 | 1. java.lang.NumberFormatException: multiple points |
같은 날짜를 파싱함에도 불구하고 비정상적으로 파싱이 되는 경우도 있었습니다.
1 | 0 : Sat Aug 19 00:00:00 KST 2220 |
정확하게 어느포인트에서 문제가 발생하는지 알고싶었지만 stackTrace를 따라서 디버깅도 해보고 했는데 정확하게 어느포인트가 문제인지는 확인하기 어려웠습니다 ㅠㅠ
1 | java.lang.NumberFormatException: multiple points |
해결책
가장 간단한건 매번 SimpleDateFormat을 만들어서 사용하는것입니다.
1
2
3
4public Date parseDate(String date) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
return simpleDateFormat.parse(date);
}synchronized 사용
1
2
3synchronized(DATE_FORMAT) {
System.out.println(seq + " : " + DATE_FORMAT.parse(date));
}DateTimeFormatter 사용
DateTimeFormatter를 사용하면 LocalDate 형태로 파싱가능하다.1
2public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(seq + " : " + LocalDate.parse(date, Utils.dateTimeFormatter));
위와같은 형태로 위에서 발생한 문제들을 해결할 수 있을것으로 생각된다.
참고
- https://stackoverflow.com/questions/6840803/
- https://knight76.tistory.com/entry/%EB%B3%91%EB%A0%AC-%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%8B%9C-Thread-Safety-%ED%99%95%EC%9D%B8%ED%95%98%EB%8A%94-%EC%8A%B5%EA%B4%80-%EA%B0%96%EA%B8%B0
- https://kldp.org/node/36904
- https://www.callicoder.com/java-simpledateformat-thread-safety-issues/
- http://wonwoo.ml/index.php/post/1759
- https://d2.naver.com/helloworld/645609