sourcecode

SimpleDateFormat에 대한 액세스 동기화

copyscript 2022. 9. 6. 22:27
반응형

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: 스레드별로 다른 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은 SimpleDateFormat의 드롭인 스레드 세이프 대체인 FastDateParser를 생성할 수 있습니다.)

Java 8 을 사용하고 있는 경우는, 다음을 사용할 수 있습니다.

이 클래스는 불변하며 스레드 세이프입니다.

예:

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이 훨씬 더 편리합니다.

예를 들어 SimpleDateFormat에 대한 접근을 parse() 및 format()에 동기화하여 드롭인 대체로 사용할 수 있는 단순한 래퍼 클래스를 만듭니다.옵션 #2보다 완전하고, 옵션 #3보다 번거롭지 않습니다.

SimpleDateFormat을 동기화하지 않은 것은 Java API 디자이너의 설계상 잘못된 결정인 것 같습니다.format()과 parse()가 동기화되어야 한다고 생각하는 사람은 없을 것 같습니다.

다른 옵션은 인스턴스를 스레드 세이프 큐에 유지하는 것입니다.

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;
}

dateFormatQueue의 크기는 이 함수를 동시에 일상적으로 호출할 수 있는 예상 스레드 수에 가까워야 합니다.이 수보다 더 많은 스레드가 실제로 모든 인스턴스를 동시에 사용하는 최악의 경우 일부 SimpleDateFormat 인스턴스가 생성되며, 이 인스턴스는 가득 찼기 때문에 dateFormatQueue로 되돌릴 수 없습니다.이로 인해 오류가 발생하는 것이 아니라 한 번만 사용되는 SimpleDateFormat을 작성해야 하는 패널티가 발생합니다.

옵션 3을 사용하여 이 기능을 구현했지만 몇 가지 코드를 변경했습니다.

  • ThreadLocal은 보통 정적이어야 합니다.
  • (get() == null) 여부를 테스트하는 대신 initialValue()를 재정의하는 것이 더 깔끔해 보입니다.
  • 디폴트 설정을 정말로 필요로 하지 않는 한, 로케일과 타임 존을 설정할 수 있습니다(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);
    }
    

응용 프로그램에 스레드가 하나 있다고 가정해 보십시오.그렇다면 SimpleDataFormat 변수에 대한 액세스를 동기화하는 이유는 무엇입니까?

언급URL : https://stackoverflow.com/questions/4107839/synchronizing-access-to-simpledateformat

반응형