Java의 SimpleDateFormat은 절대 Simple하지 않습니다.
멀티 스레드 환경이면 더더욱이요.
다음과 같은 코드를 실행해 봅니다.
import java.text.SimpleDateFormat
import java.util.Date
import scala.concurrent._
import ExecutionContext.Implicits.global
val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
def fmtFuture(dateStr: String): Future[Date] = Future {
format.parse(dateStr)
}
val parseList: Seq[Future[Date]] = (1 to 10).map(i => "2021-01-18 20:00:0" + i % 10).map(ts => fmtFuture(ts))
parseList foreach println
Thread.sleep(3000)
실행 결과는 다음과 같습니다 :
import java.text.SimpleDateFormat import java.util.Date import scala.concurrent._ import ExecutionContext.Implicits.global format: java.text.SimpleDateFormat = java.text.SimpleDateFormat@4f76f1a0 fmtFuture: (dateStr: String)scala.concurrent.Future[java.util.Date] parseList: Seq[scala.concurrent.Future[java.util.Date]] = Vector(Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>), Future(<not completed>)) Future(Success(Wed Jan 18 07:33:41 KST 2)) Future(Success(Mon Jan 18 20:00:02 KST 2021)) Future(Success(Mon Jan 18 20:00:02 KST 2021)) Future(Success(Wed Jan 18 07:33:41 KST 2)) Future(Success(Mon Jan 18 20:00:05 KST 2021)) Future(Success(Mon Jan 18 20:00:06 KST 2021)) Future(Success(Mon Jan 18 20:00:07 KST 2021)) Future(Failure(java.lang.NumberFormatException: For input string: "")) Future(Success(Fri Jul 09 20:00:01 KST 202)) Future(Success(Mon Jan 18 20:00:00 KST 2021)) |
띠용 전혀 의도치 않은 결과가 나왔습니다.
2021년 1월 18일 20시 00분 00~09초의 시간대가 입력되었을텐데, 출력물은 온갖 이상한 날짜로 변해있습니다.
이는 Java의 SimpleDateFormat이 Thread-Safe하지 않기 때문입니다.
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
StackOverFlow의 관련 글 : stackoverflow.com/questions/6840803/why-is-javas-simpledateformat-not-thread-safe
따라서 다중 스레드 환경에서 동시에 하나의 SimpleDateFormat에 접근하는 경우 문제가 발생합니다.
이런 의도치 않은 결과물이 등장하는것을 막기 위해서는 SimpleDateFormat 객체를 매 스레드마다 새로 생성하거나, Java8부터 도입된 DateTimeFormatter나 joda.time의 DateTimeFormat를 사용해야 합니다.
Java8의 DateTimeFormatter 사용
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import scala.concurrent._
import ExecutionContext.Implicits.global
val format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
def fmtFuture(str: String): Future[LocalDateTime] = Future {
LocalDateTime.parse(str, format)
}
val parseList: Seq[Future[LocalDateTime]] = (1 to 10).map(i => "2021-01-18 20:00:0" + i % 10).map(ts => fmtFuture(ts))
parseList foreach println
Thread.sleep(3000)
joda.time의 DateTimeFormat 사용
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import scala.concurrent._
import ExecutionContext.Implicits.global
val format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
def fmtFuture(str: String): Future[DateTime] = Future {
DateTime.parse(str, format)
}
val parseList: Seq[Future[DateTime]] = (1 to 10).map(i => "2021-01-18 20:00:0" + i % 10).map(ts => fmtFuture(ts))
parseList foreach println
Thread.sleep(3000)
실제 위 두 코드는 정상적인 결과물을 반환합니다.