SimpleDateFormat तक पहुंच को सिंक्रनाइज़ करना


90

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 का एक अलग उदाहरण संग्रहीत करने के लिए एक ThreadLocal बनाएँ।

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

10
इस मुद्दे को उठाने के लिए +1। इतने सारे लोग सोचते हैं कि SimpleDateFormat थ्रेड सुरक्षित है (मैं हर जगह मान्यताओं को देखता हूं)।
एडम जेंट


और क्यों, इस प्रश्न को देखें: stackoverflow.com/questions/6840803/…
Raedwald

@ 3urdoch क्या आपने विकल्प -2 में गलती से 'स्थिर' कीवर्ड छोड़ दिया था?
एम फैसल हमीद

जवाबों:


43
  1. SimpleDateFormat बनाना महंगा है । इसका उपयोग तब तक न करें जब तक कि यह शायद ही कभी किया गया हो।

  2. ठीक है अगर आप थोड़ा अवरुद्ध के साथ रह सकते हैं। अगर FormatDate () का उपयोग ज्यादा नहीं किया गया है।

  3. सबसे तेज़ विकल्प यदि आप थ्रेड्स ( थ्रेड पूल ) का पुन: उपयोग करते हैं । 2 से अधिक मेमोरी का उपयोग करता है और इसमें अधिक स्टार्टअप ओवरहेड है।

अनुप्रयोगों के लिए 2. और 3. दोनों व्यवहार्य विकल्प हैं। जो आपके मामले के लिए सबसे अच्छा है, आपके उपयोग के मामले पर निर्भर करता है। समयपूर्व अनुकूलन से सावधान रहें। यदि आप मानते हैं कि यह एक मुद्दा है तो ही इसे करें।

3 पार्टी द्वारा इस्तेमाल किया जाएगा पुस्तकालयों के लिए मैं विकल्प 3 का उपयोग करेंगे।


यदि हम Option-2 का उपयोग करते हैं और SimpleDateFormatउदाहरण चर के रूप में घोषित करते हैं तो हम synchronized blockइसे थ्रेड-सुरक्षित बनाने के लिए उपयोग कर सकते हैं । लेकिन सोनार चेतावनी स्क्वीड-AS2885 दिखाता है । क्या सोनार मुद्दे को हल करने का कोई तरीका है?
एम फैसल हमीद

24

दूसरा विकल्प कॉमन्स लैंग फास्टटैर्मफॉर्म है लेकिन आप इसे केवल तारीख स्वरूपण और पार्सिंग के लिए उपयोग कर सकते हैं।

जोडा के विपरीत, यह प्रारूपण के लिए ड्रॉप-इन प्रतिस्थापन के रूप में कार्य कर सकता है। (अपडेट: v3.3.2 के बाद से, FastDateFormat FastDateParser का उत्पादन कर सकता है , जो कि SimpleDateFormat के लिए ड्रॉप-इन थ्रेड-सुरक्षित प्रतिस्थापन है)


8
चूंकि कॉमन्स लैंग 3.2, FastDateFormatमें parse()विधि है
मनुना

19

यदि आप जावा 8 का उपयोग कर रहे हैं, तो आप उपयोग करना चाह सकते हैं java.time.format.DateTimeFormatter:

यह वर्ग अपरिवर्तनीय और धागा-सुरक्षित है।

उदाहरण के लिए:

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

6

कॉमन्स लैंग 3.x में अब FastDateParser के साथ-साथ FastDateFormat भी है। यह SimpleDateFormat की तुलना में सुरक्षित और तेज़ है। यह भी SimpleDateFormat के रूप में एक ही प्रारूप / पार्स पैटर्न विनिर्देशों का उपयोग करता है।


यह केवल 3.2+ में उपलब्ध है और 3.x पर नहीं
विस्टेसो

4

SimpleDateFormat का उपयोग न करें, इसके बजाय joda-time के DateTimeFormatter का उपयोग करें। यह पार्सिंग साइड में थोड़ा सख्त है और इसलिए SimpleDateFormat के प्रतिस्थापन में काफी गिरावट नहीं है, लेकिन सुरक्षा और प्रदर्शन के मामले में joda-time अधिक समवर्ती अनुकूल है।


3

मैं कहूंगा, SimpleDateFormat के लिए एक सरल आवरण-वर्ग बनाएं जो पार्स () और प्रारूप () तक पहुंच को सिंक्रनाइज़ करता है और इसे ड्रॉप-इन प्रतिस्थापन के रूप में उपयोग किया जा सकता है। आपके विकल्प # 2 से अधिक मूर्ख, आपके विकल्प # 3 से कम बोझिल।

SimpleDateFormat को अनसिंक्रनाइज्ड बनाने जैसा लगता है जावा एपीआई डिजाइनरों की ओर से एक खराब डिजाइन निर्णय था; मुझे संदेह है कि किसी को भी प्रारूप () और पार्स () को सिंक्रनाइज़ करने की आवश्यकता है।


1

एक अन्य विकल्प थ्रेड-सेफ कतार में उदाहरण रखना है:

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 इंस्टेंस बनाए जाएंगे, जिन्हें पूर्ण नहीं किया जा सकता क्योंकि यह पूर्ण है। यह एक त्रुटि उत्पन्न नहीं करेगा, यह सिर्फ कुछ SimpleDateFormat बनाने का जुर्माना लगाएगा जो केवल एक बार उपयोग किए जाते हैं।


1

मैंने इसे विकल्प 3 के साथ लागू किया, लेकिन कुछ कोड परिवर्तन किए:

  • थ्रेडलोक आमतौर पर स्थिर होना चाहिए
  • लगता है कि क्लीनर को शुरू करने के बजाय () () (= = null) के बजाय परीक्षण से हटा दें
  • आप लोकल और टाइम ज़ोन सेट करना चाह सकते हैं जब तक कि आप वास्तव में डिफ़ॉल्ट सेटिंग्स नहीं चाहते हैं (चूक जावा के साथ बहुत त्रुटि वाले हैं)

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

0

कल्पना कीजिए कि आपके आवेदन में एक धागा है। आप SimpleDataFormat चर तक पहुँच को फिर से क्यों सिंक्रनाइज़ करेंगे?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.