복붙노트

[SPRING] thread 안전에 관한 혼란 - SimpleDateFormat의 예

SPRING

thread 안전에 관한 혼란 - SimpleDateFormat의 예

스레드 안전성에 대한 질문이 있습니다. 내가 말한 바로는 SimpleDateFormat은 쓰레드에 안전하지 않습니다. 스프링 컨트롤러에서 다음과 같은 방법으로 사용하면 어떤 효과가 있는지 궁금합니다.

private final static SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);

나중에 내 컨트롤러 기능 중 하나에서 다음과 같이 사용합니다.

  try {
        changedate = changedate.substring(0, 15);                                                
        calcDate = dateFormat.parse(changedate);
    } catch (ParseException e2) {
        logger.error("Date Parsing Problem", e2); 
    }

그런 다음 calcDate가 내 모델 객체에 추가되고 ModelAndView가 반환됩니다.

그렇다면이 방법을 사용하면 어떤 종류의 문제가 발생합니까? 각 스레드가 dateFormat의 자체 인스턴스를 사용할 것이기 때문에 정적 키워드를 제거하면 문제가 해결됩니까? 스레드 보안과 관련하여이 하위 섹션의 명확성은 매우 높이 평가됩니다.

감사

해결법

  1. ==============================

    1.SimpleDateFormat.parse ()는 calendar라는 인스턴스 변수를 사용하여 문자열에서 날짜를 만듭니다. 두 스레드가 동시에 구문 분석을 시도하면 캘린더 변수가 달라지며 잘못된 결과가 나옵니다.

    SimpleDateFormat.parse ()는 calendar라는 인스턴스 변수를 사용하여 문자열에서 날짜를 만듭니다. 두 스레드가 동시에 구문 분석을 시도하면 캘린더 변수가 달라지며 잘못된 결과가 나옵니다.

    두 스레드가 여전히 동일한 컨트롤러를 사용할 수 있기 때문에 변수를 정적으로 만들지 않아도 도움이되지는 않습니다. 더 나은 해결책은 날짜를 구문 분석 할 때마다 새 DateFormat 객체를 만들거나 스레드 로컬 저장소를 사용하는 것입니다. 더 나은 여전히 ​​스레드 안전 파서가있는 JodaTime을 사용하십시오.

  2. ==============================

    2.SimpleDateFormat 개발자는 parse () 작업 중에 SimpleDateFormat 필드에 부분적으로 파싱 된 날짜를 저장하는 매우 이상한 결정을 내 렸습니다. 분명히, 그것은 여러 스레드에서 parse ()를 동시에 호출 할 수 없다는 것을 의미합니다.

    SimpleDateFormat 개발자는 parse () 작업 중에 SimpleDateFormat 필드에 부분적으로 파싱 된 날짜를 저장하는 매우 이상한 결정을 내 렸습니다. 분명히, 그것은 여러 스레드에서 parse ()를 동시에 호출 할 수 없다는 것을 의미합니다.

    정적 제거는 도움이되지 않습니다. 스프링 컨트롤러는 기본적으로 싱글 톤 범위이므로, 스프링은 컨트롤러의 단일 인스턴스를 사용하여 모든 요청을 처리합니다.

  3. ==============================

    3.개인적으로 JodaTime을 사용하여 이러한 모든 문제를 피할 수 있습니다. API는 훨씬 더 풍부하고 스레딩 문제가 없으며 훨씬 빠릅니다.

    개인적으로 JodaTime을 사용하여 이러한 모든 문제를 피할 수 있습니다. API는 훨씬 더 풍부하고 스레딩 문제가 없으며 훨씬 빠릅니다.

  4. ==============================

    4.SimpleDateFormat는 파싱하는 동안 인스턴스 전체의 상태를 가지므로 스레드로부터 안전하지 않습니다. 여러 스레드에서 사용하는 경우 충돌이 발생합니다 (Java 충돌 :-), 프로세스 충돌 없음 등). 정적 키워드를 제거해도 문제가 해결되는 것은 아니지만 인스턴스에 따라 달라지며 여전히 여러 스레드에서 사용될 수 있습니다.

    SimpleDateFormat는 파싱하는 동안 인스턴스 전체의 상태를 가지므로 스레드로부터 안전하지 않습니다. 여러 스레드에서 사용하는 경우 충돌이 발생합니다 (Java 충돌 :-), 프로세스 충돌 없음 등). 정적 키워드를 제거해도 문제가 해결되는 것은 아니지만 인스턴스에 따라 달라지며 여전히 여러 스레드에서 사용될 수 있습니다.

    위의 메서드 내에서 로컬 인스턴스를 만들어 각 구문 분석이 자체 포맷터로 발생하거나 스레드 로컬 변수로 재생되도록 할 수 있습니다.

  5. ==============================

    5.이런 식으로하면 어떤 유형의 문제가 나타날지 확신 할 수 없습니다. 그러나 Javadocs는 SimpleDateFormat에 동시 액세스하지 못하도록 경고하고이를 사용하는 경우 동시 액세스가 반드시 필요합니다. 정적 클래스를 제거해도 포함 된 클래스에 대해 일부 유형의 동기화 정책을 구현하지 않았거나 여러 스레드가 클래스에 액세스하지 못하는 경우가 아니면 동시성 문제가 제거되지 않습니다.

    이런 식으로하면 어떤 유형의 문제가 나타날지 확신 할 수 없습니다. 그러나 Javadocs는 SimpleDateFormat에 동시 액세스하지 못하도록 경고하고이를 사용하는 경우 동시 액세스가 반드시 필요합니다. 정적 클래스를 제거해도 포함 된 클래스에 대해 일부 유형의 동기화 정책을 구현하지 않았거나 여러 스레드가 클래스에 액세스하지 못하는 경우가 아니면 동시성 문제가 제거되지 않습니다.

    메서드의 본체 내에서 인스턴스화 해, SimpleDateFormat 에의 참조가 결코 메소드를 "이스케이프"하지 않게 해, 각 thread의 SimpleDateFormat를 작성할 수 있습니다. 즉, 변수를 선언하고 객체를 인스턴스화 한 다음 동일한 메소드 내에서 객체를 사용합니다. 이것에 의해, 메서드의 종료시에 그 SimpleDateFormat의 참조가 삭제됩니다.

  6. ==============================

    6.안드로이드 개발자는 SimpleDateFormat을 중심으로 안전한 (스레드 현지화 된) 래퍼를 사용할 수 있습니다 : org.apache.http.impl.cookie.DateUtils

    안드로이드 개발자는 SimpleDateFormat을 중심으로 안전한 (스레드 현지화 된) 래퍼를 사용할 수 있습니다 : org.apache.http.impl.cookie.DateUtils

    구현 소스 코드는 여기에 있습니다 (예 : FROYO API 레벨 8).

  7. ==============================

    7.또 다른 방법은 컨트롤러가 호출 될 때마다 보장 할 수 있으면 새 인스턴스를 반환 한 다음 정적 참조를 제거하는 것입니다.

    또 다른 방법은 컨트롤러가 호출 될 때마다 보장 할 수 있으면 새 인스턴스를 반환 한 다음 정적 참조를 제거하는 것입니다.

  8. from https://stackoverflow.com/questions/5652518/confusion-about-thread-safety-simpledateformat-example by cc-by-sa and MIT license