IT story

SimpleDateFormat에 대한 액세스 동기화

hot-time 2020. 9. 14. 21:41
반응형

SimpleDateFormat에 대한 액세스 동기화


SimpleDateFormat에 대한 javadoc은 SimpleDateFormat이 동기화되지 않음을 나타냅니다.

"날짜 형식은 동기화되지 않습니다. 각 스레드에 대해 별도의 형식 인스턴스를 만드는 것이 좋습니다. 여러 스레드가 동시에 형식에 액세스하는 경우 외부에서 동기화해야합니다."

그러나 다중 스레드 환경에서 SimpleDateFormat의 인스턴스를 사용하는 가장 좋은 방법은 무엇입니까? 내가 생각한 몇 가지 옵션이 있습니다. 과거에 옵션 1과 2를 사용했지만 더 나은 대안이 있는지 또는 이러한 옵션 중 어떤 옵션이 최고의 성능과 동시성을 제공하는지 알고 싶습니다.

옵션 1 : 필요한 경우 로컬 인스턴스 생성

public String formatDate(Date d) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    return sdf.format(d);
}

옵션 2 : SimpleDateFormat의 인스턴스를 클래스 변수로 생성하지만 이에 대한 액세스를 동기화합니다.

private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String formatDate(Date d) {
    synchronized(sdf) {
        return sdf.format(d);
    }
}

옵션 3 : ThreadLocal을 생성하여 각 스레드에 대해 SimpleDateFormat의 다른 인스턴스를 저장합니다.

private ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>();
public String formatDate(Date d) {
    SimpleDateFormat sdf = tl.get();
    if(sdf == null) {
        sdf = new SimpleDateFormat("yyyy-MM-hh");
        tl.set(sdf);
    }
    return sdf.format(d);
}

  1. SimpleDateFormat을 만드는 것은 비용많이 듭니다 . 드물게 사용하지 않는 한 이것을 사용하지 마십시오.

  2. 당신이 약간의 차단으로 살 수 있다면 좋습니다. formatDate ()가 많이 사용되지 않는 경우 사용하십시오.

  3. 스레드를 재사용하는 경우 가장 빠른 옵션 ( 스레드 풀 ). 2보다 많은 메모리를 사용하고 시작 오버 헤드가 더 높습니다.

응용 프로그램의 경우 2.와 3. 모두 실행 가능한 옵션입니다. 귀하의 사례에 가장 적합한 것은 사용 사례에 따라 다릅니다. 조기 최적화에주의하십시오. 이것이 문제라고 생각하는 경우에만 수행하십시오.

타사에서 사용할 라이브러리의 경우 옵션 3을 사용합니다.


다른 옵션은 Commons Lang FastDateFormat 이지만 파싱이 아닌 날짜 형식에만 사용할 수 있습니다.

Joda와 달리 서식 지정을위한 드롭 인 대체 기능을 수행 할 수 있습니다. (업데이트 : V3.3.2 때문에 FastDateFormat는 생산할 수 FastDateParser 드롭 인 SimpleDateFormat에 대한 스레드 안전 여분이다)


Java 8을 사용하는 경우 java.time.format.DateTimeFormatter다음 을 사용할 수 있습니다 .

이 클래스는 변경 불가능하고 스레드로부터 안전합니다.

예 :

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String str = new java.util.Date().toInstant()
                                 .atZone(ZoneId.systemDefault())
                                 .format(formatter);

Commons Lang 3.x에는 이제 FastDateParser와 FastDateFormat이 있습니다. 스레드로부터 안전하고 SimpleDateFormat보다 빠릅니다. 또한 SimpleDateFormat과 동일한 형식 / 분석 패턴 사양을 사용합니다.


SimpleDateFormat을 사용하지 말고 대신 joda-time의 DateTimeFormatter를 사용하십시오. 구문 분석 측면에서 약간 더 엄격하므로 SimpleDateFormat의 대체물이 크게 떨어지지는 않지만 joda-time은 안전성과 성능면에서 훨씬 더 친숙합니다.


I would say, create a simple wrapper-class for SimpleDateFormat that synchronizes access to parse() and format() and can be used as a drop-in replacement. More foolproof than your option #2, less cumbersome than your option #3.

Seems like making SimpleDateFormat unsynchronized was a poor design decision on the part of the Java API designers; I doubt anyone expects format() and parse() to need to be synchronized.


Another option is to keep instances in a thread-safe queue:

import java.util.concurrent.ArrayBlockingQueue;
private static final int DATE_FORMAT_QUEUE_LEN = 4;
private static final String DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
private ArrayBlockingQueue<SimpleDateFormat> dateFormatQueue = new ArrayBlockingQueue<SimpleDateFormat>(DATE_FORMAT_QUEUE_LEN);
// thread-safe date time formatting
public String format(Date date) {
    SimpleDateFormat fmt = dateFormatQueue.poll();
    if (fmt == null) {
        fmt = new SimpleDateFormat(DATE_PATTERN);
    }
    String text = fmt.format(date);
    dateFormatQueue.offer(fmt);
    return text;
}
public Date parse(String text) throws ParseException {
    SimpleDateFormat fmt = dateFormatQueue.poll();
    if (fmt == null) {
        fmt = new SimpleDateFormat(DATE_PATTERN);
    }
    Date date = null;
    try {
        date = fmt.parse(text);
    } finally {
        dateFormatQueue.offer(fmt);
    }
    return date;
}

The size of dateFormatQueue should be something close to the estimated number of threads which can routinely call this function at the same time. In the worst case where more threads than this number do actually use all the instances concurrently, some SimpleDateFormat instances will be created which cannot be returned to dateFormatQueue because it is full. This will not generate an error, it will just incur the penalty of creating some SimpleDateFormat which are used only once.


I just implemented this with Option 3, but made a few code changes:

  • ThreadLocal should usually be static
  • Seems cleaner to override initialValue() rather than test if (get() == null)
  • You may want to set locale and time zone unless you really want the default settings (defaults are very error prone with Java)

    private static final ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-hh", Locale.US);
            sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
            return sdf;
        }
    };
    public String formatDate(Date d) {
        return tl.get().format(d);
    }
    

Imagine your application has one thread. Why would you synchronize access to SimpleDataFormat variable then?

참고URL : https://stackoverflow.com/questions/4107839/synchronizing-access-to-simpledateformat

반응형