दिलचस्प पोस्ट
इकाई फ़्रेमवर्क। निकालें () बनाम। Delete ऑब्जेक्ट () कैसे जावा में कस्टम अपवाद बनाने के लिए? पायथन में खाली सूची बनाना जावास्क्रिप्ट में कई पंक्तियों में एक लंबी नियमित अभिव्यक्ति कैसे विभाजित है? कंपाइलर संदिग्ध आवेश त्रुटि – गुंजाइश विधि और फ़ंक्शन के साथ विधि समूह <> या क्रिया एंड्रॉइड जावा और फोनगैप जावास्क्रिप्ट के बीच संचार? क्या फॉर्मेटिंग को तोड़ने के बिना सीएसवी कॉलम में कॉमा को शामिल करने का कोई तरीका है? निष्पादक.न्यूकैचड थ्रेडपूल () बनाम निष्पादक। एनवेफिक्सट्रेडपूल () जावास्क्रिप्ट ऑब्जेक्ट ब्रैकेट नोटेशन ({नेविगेशन} =) को असाइन करने की बाईं तरफ कस्टम फ़ॉन्ट्स के साथ XCode6 आकार क्लासेस में कस्टम फॉन्ट साइजिंग ठीक से काम नहीं कर रहा है जीएसएन से जेसन ने एक जेसन सिंटटाक्स को क्यों फेंक दिया है: कुछ प्रकार की उम्मीद है लेकिन कुछ अन्य प्रकार हैं? यह कैन पढ़ने क्यों जाम है? विंडोज 8 पर कड़ाही: 'घुरघुर' मान्यता प्राप्त नहीं है सीएसएस पृष्ठभूमि अस्पष्टता विजुअल स्टूडियो "बिल्डिंग के दौरान …" कॉपी नहीं कर सके

"जावा तिथि स्वरूप धागा सुरक्षित नहीं है" यह क्या होता है?

हर कोई जावा के बारे में चेतावनी DateFormat धागा सुरक्षित नहीं किया जा रहा है और मैं सैद्धांतिक रूप से अवधारणा को समझता हूं।

लेकिन मैं इस बात की कल्पना नहीं कर पा रहा हूं कि हम इस वास्तविक वजह से क्यों सामना कर सकते हैं। कहते हैं, मेरे पास एक वर्ग में एक dateFormat फ़ील्ड है और यह एक बहु-थ्रेडेड परिवेश में क्लास (स्वरूपण दिनांक) के विभिन्न तरीकों में उपयोग किया जाता है।

इस कारण होगा:

  • प्रारूप अपवाद की तरह कोई अपवाद
  • डेटा में विसंगति
  • कोई अन्य मुद्दा?

इसके अलावा, कृपया बताएं कि क्यों

वेब के समाधान से एकत्रित समाधान ""जावा तिथि स्वरूप धागा सुरक्षित नहीं है" यह क्या होता है?"

आइए इसे आज़माएं।

यहां एक ऐसा कार्यक्रम है जिसमें कई थ्रेड्स साझा किए गए SimpleDateFormat उपयोग करते हैं।

कार्यक्रम :

 public static void main(String[] args) throws Exception { final DateFormat format = new SimpleDateFormat("yyyyMMdd"); Callable<Date> task = new Callable<Date>(){ public Date call() throws Exception { return format.parse("20101022"); } }; //pool with 5 threads ExecutorService exec = Executors.newFixedThreadPool(5); List<Future<Date>> results = new ArrayList<Future<Date>>(); //perform 10 date conversions for(int i = 0 ; i < 10 ; i++){ results.add(exec.submit(task)); } exec.shutdown(); //look at the results for(Future<Date> result : results){ System.out.println(result.get()); } } 

इसे कई बार चलाएं और आप देखेंगे:

अपवाद :

कुछ उदाहरण निम्नलिखित हैं:

1।

 Caused by: java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Long.parseLong(Long.java:431) at java.lang.Long.parseLong(Long.java:468) at java.text.DigitList.getLong(DigitList.java:177) at java.text.DecimalFormat.parse(DecimalFormat.java:1298) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589) 

2।

 Caused by: java.lang.NumberFormatException: For input string: ".10201E.102014E4" at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224) at java.lang.Double.parseDouble(Double.java:510) at java.text.DigitList.getDouble(DigitList.java:151) at java.text.DecimalFormat.parse(DecimalFormat.java:1303) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589) 

3।

 Caused by: java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084) at java.lang.Double.parseDouble(Double.java:510) at java.text.DigitList.getDouble(DigitList.java:151) at java.text.DecimalFormat.parse(DecimalFormat.java:1303) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1936) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312) 

गलत परिणाम :

 Sat Oct 22 00:00:00 BST 2011 Thu Jan 22 00:00:00 GMT 1970 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Thu Oct 22 00:00:00 GMT 1970 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 

सही परिणाम :

 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 Fri Oct 22 00:00:00 BST 2010 

एक बहु-थ्रेडेड वातावरण में DateFormats का सुरक्षित उपयोग करने के लिए एक और तरीका है DateFormat ऑब्जेक्ट को पकड़ने के लिए ThreadLocal वेरिएबल का उपयोग करना, जिसका अर्थ है कि प्रत्येक थ्रेड की अपनी प्रति होगी और अन्य धागे को इसे रिलीज़ करने के लिए प्रतीक्षा करने की आवश्यकता नहीं है इस तरह से:

 public class DateFormatTest { private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyyMMdd"); } }; public Date convert(String source) throws ParseException{ Date d = df.get().parse(source); return d; } } 

यहां अधिक विवरण के साथ एक अच्छी पोस्ट है ।

मुझे डेटा भ्रष्टाचार की उम्मीद है – जैसे अगर आप एक ही समय में दो तिथियां पार्स कर रहे हैं, तो आप एक दूसरे से डेटा के जरिए एक कॉल प्रदूषित कर सकते हैं।

यह कल्पना करना आसान होता है कि यह कैसे हो सकता है: पार्सिंग में अक्सर कुछ खास राज्य बनाए रखना शामिल है जो आपने पढ़ा है। यदि दो धागे एक ही राज्य पर कूड़ाएं हैं, तो आपको समस्याएं मिल जाएंगी। उदाहरण के लिए, DateFormat calendar प्रकार के calendar पर्दाफाश करता है, और SimpleDateFormat के कोड को SimpleDateFormat , कुछ तरीकों को calendar.set(...) कॉल calendar.set(...) और अन्य calendar.get(...) . SimpleDateFormat calendar.set(...) कॉल करते हैं। यह स्पष्ट रूप से धागा-सुरक्षित नहीं है

मैंने सटीक विवरण नहीं देखा है क्यों DateFormat धागा-सुरक्षित नहीं है, लेकिन मेरे लिए यह जानने के लिए पर्याप्त है कि यह सिंक्रनाइज़ेशन के बिना असुरक्षित है – गैर-सुरक्षा के सटीक व्यवहार भी विज्ञप्ति के बीच बदल सकते हैं

निजी तौर पर मैं जौदा समय से पार्सर का प्रयोग करूँगा, क्योंकि वे थ्रेड सुरक्षित हैं – और जोडा टाइम एक बेहतर तिथि और समय एपीआई है जिसकी शुरुआत के साथ 🙂

मोटे तौर पर, आपको किसी DateFormat को परिभाषित नहीं करना चाहिए, जैसा कि कई थ्रेडों द्वारा उपयोग किए गए ऑब्जेक्ट के उदाहरण चर, या static

दिनांक प्रारूप सिंक्रनाइज़ नहीं होते हैं प्रत्येक थ्रेड के लिए अलग प्रारूप उदाहरण बनाने की सिफारिश की जाती है।

इसलिए, यदि आपके Foo.handleBar(..) को एकाधिक थ्रेड द्वारा एक्सेस किया जाता है, तो इसके बजाय:

 public class Foo { private DateFormat df = new SimpleDateFormat("dd/mm/yyyy"); public void handleBar(Bar bar) { bar.setFormattedDate(df.format(bar.getStringDate()); } } 

आपको उपयोग करना चाहिए:

 public class Foo { public void handleBar(Bar bar) { DateFormat df = new SimpleDateFormat("dd/mm/yyyy"); bar.setFormattedDate(df.format(bar.getStringDate()); } } 

इसके अलावा, सभी मामलों में, एक static DateFormat नहीं है

जैसा जॉन स्कीट द्वारा नोट किया गया है, यदि आप बाहरी सिंक्रनाइज़ेशन करते हैं, तो आप स्थिर और साझा आवृत्ति चर दोनों हो सकते हैं (अर्थात DateFormat को कॉल के आसपास synchronized करने के लिए)

यदि आप जावा 8 का उपयोग कर रहे हैं तो आप DateTimeFormatter उपयोग कर सकते हैं।

एक प्रारूप से बनाया गया एक फॉर्मेटर जितनी बार आवश्यक हो सकता है, यह अपरिवर्तनीय है और धागा-सुरक्षित है

कोड:

 LocalDate date = LocalDate.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String text = date.format(formatter); System.out.println(text); 

आउटपुट:

 2017-04-17 

दिनांक प्रारूप सिंक्रनाइज़ नहीं होते हैं प्रत्येक थ्रेड के लिए अलग प्रारूप उदाहरण बनाने की सिफारिश की जाती है। यदि एकाधिक थ्रेड समवर्ती रूप से एक प्रारूप का उपयोग करते हैं, तो इसे बाह्य रूप से सिंक्रनाइज़ किया जाना चाहिए

इसका अर्थ है कि आपके पास डेटफॉर्मैट का एक ऑब्जेक्ट है और आप दो ऑब्जेक्ट्स से उसी ऑब्जेक्ट को एक्सेस कर रहे हैं और आप उस ऑब्जेक्ट पर फॉर्मेट विधि को बुला रहे हैं, दोनों थ्रेड उसी ऑब्जेक्ट पर एक ही ऑब्जेक्ट पर एक ही ऑब्जेक्ट में प्रवेश करेगा ताकि आप इसे विजुअलाइज़ कर सकें उचित परिणाम में परिणाम नहीं

अगर आपको तिथि फॉर्मेट के साथ काम करना है तो आप कुछ करना चाहिए

 public synchronized myFormat(){ // call here actual format method } 
  • संदर्भ

डेटा दूषित है कल मैंने इसे अपने मल्टीथ्रेड प्रोग्राम में देखा था, जहां मेरे पास स्थैतिक DateFormat ऑब्जेक्ट था और जेडीबीसी के माध्यम से पढ़े गए मूल्यों के लिए इसका format() कहा जाता है मेरे पास एसक्यूएल चयन बयान था, जहां मैंने उसी तारीख को अलग-अलग नामों के साथ पढ़ा था ( SELECT date_from, date_from AS date_from1 ... )। ऐसे वक्तव्य में विभिन्न धागे के लिए 5 धागे में WHERE क्लासेस में उपयोग किया गया था। तिथियां "सामान्य" दिखती हैं, लेकिन वे मूल्य में मतभेद करते थे – जबकि सभी तिथियां उसी वर्ष से थीं, केवल महीने और दिन बदलते थे।

दूसरे जवाब आपको इस तरह के भ्रष्टाचार से बचने का तरीका दिखाते हैं। मैंने अपना DateFormat स्थिर नहीं बनाया, अब यह एक क्लास का सदस्य है जो एसक्यूएल स्टेटमेंट को कॉल करता है। मैंने सिंक्रनाइज़िंग के साथ भी स्थिर संस्करण का परीक्षण किया। दोनों प्रदर्शन में कोई अंतर नहीं के साथ अच्छी तरह से काम किया।

प्रारूप, संख्या प्रारूप, तिथि प्रारूप, संदेशफ़ॉर्मेट आदि की विशिष्टताओं को धागा-सुरक्षित होने के लिए तैयार नहीं किया गया था। इसके अलावा, पार्स विधि कैलेंडर.क्लोन Calendar.clone() विधि पर कॉल करती है और यह कैलेंडर के पैरों के निशान को प्रभावित करती है, इसलिए कई थ्रेड समान रूप से पार्स करने से कैलेंडर इंस्टेंस के क्लोनिंग को बदल देगा।

अधिक के लिए, ये बग रिपोर्ट हैं जैसे कि यह और यह , DateFormat धागा-सुरक्षा समस्या के परिणाम के साथ।

यदि एकाधिक थ्रेड्स हैं जो किसी एकल dateFormat इंस्टेंस और सिंक्रनाइज़ेशन का उपयोग नहीं करते हैं, तो इसका उपयोग करना संभव है, तले हुए परिणाम प्राप्त करना संभव है। ऐसा इसलिए है क्योंकि कई गैर-परमाणु आपरेशन राज्य को बदल सकते हैं या स्मृति को असंगत रूप से देख सकते हैं

यह मेरा सरल कोड है जो कि पता चलता है कि प्रारूप फ़ार्मैट सुरक्षित नहीं है

 import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class DateTimeChecker { static DateFormat df = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy", Locale.ENGLISH); public static void main(String args[]){ String target1 = "Thu Sep 28 20:29:30 JST 2000"; String target2 = "Thu Sep 28 20:29:30 JST 2001"; String target3 = "Thu Sep 28 20:29:30 JST 2002"; runThread(target1); runThread(target2); runThread(target3); } public static void runThread(String target){ Runnable myRunnable = new Runnable(){ public void run(){ Date result = null; try { result = df.parse(target); } catch (ParseException e) { e.printStackTrace(); System.out.println("Ecxfrt"); } System.out.println(Thread.currentThread().getName() + " " + result); } }; Thread thread = new Thread(myRunnable); thread.start(); } } 

चूंकि सभी थ्रेड समान SimpleDateFormat ऑब्जेक्ट का उपयोग कर रहे हैं, इसलिए यह निम्नलिखित अपवाद फेंकता है।

 Exception in thread "Thread-0" Exception in thread "Thread-2" Exception in thread "Thread-1" java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source) at sun.misc.FloatingDecimal.parseDouble(Unknown Source) at java.lang.Double.parseDouble(Unknown Source) at java.text.DigitList.getDouble(Unknown Source) at java.text.DecimalFormat.parse(Unknown Source) at java.text.SimpleDateFormat.subParse(Unknown Source) at java.text.SimpleDateFormat.parse(Unknown Source) at java.text.DateFormat.parse(Unknown Source) at DateTimeChecker$1.run(DateTimeChecker.java:24) at java.lang.Thread.run(Unknown Source) java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source) at sun.misc.FloatingDecimal.parseDouble(Unknown Source) at java.lang.Double.parseDouble(Unknown Source) at java.text.DigitList.getDouble(Unknown Source) at java.text.DecimalFormat.parse(Unknown Source) at java.text.SimpleDateFormat.subParse(Unknown Source) at java.text.SimpleDateFormat.parse(Unknown Source) at java.text.DateFormat.parse(Unknown Source) at DateTimeChecker$1.run(DateTimeChecker.java:24) at java.lang.Thread.run(Unknown Source) java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source) at sun.misc.FloatingDecimal.parseDouble(Unknown Source) at java.lang.Double.parseDouble(Unknown Source) at java.text.DigitList.getDouble(Unknown Source) at java.text.DecimalFormat.parse(Unknown Source) at java.text.SimpleDateFormat.subParse(Unknown Source) at java.text.SimpleDateFormat.parse(Unknown Source) at java.text.DateFormat.parse(Unknown Source) at DateTimeChecker$1.run(DateTimeChecker.java:24) at java.lang.Thread.run(Unknown Source) 

लेकिन अगर हम विभिन्न थ्रेड्स के लिए अलग-अलग ऑब्जेक्ट पास करते हैं, तो कोड बिना त्रुटियों के चलाता है।

 import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class DateTimeChecker { static DateFormat df; public static void main(String args[]){ String target1 = "Thu Sep 28 20:29:30 JST 2000"; String target2 = "Thu Sep 28 20:29:30 JST 2001"; String target3 = "Thu Sep 28 20:29:30 JST 2002"; df = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy", Locale.ENGLISH); runThread(target1, df); df = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy", Locale.ENGLISH); runThread(target2, df); df = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy", Locale.ENGLISH); runThread(target3, df); } public static void runThread(String target, DateFormat df){ Runnable myRunnable = new Runnable(){ public void run(){ Date result = null; try { result = df.parse(target); } catch (ParseException e) { e.printStackTrace(); System.out.println("Ecxfrt"); } System.out.println(Thread.currentThread().getName() + " " + result); } }; Thread thread = new Thread(myRunnable); thread.start(); } } 

ये परिणाम हैं

 Thread-0 Thu Sep 28 17:29:30 IST 2000 Thread-2 Sat Sep 28 17:29:30 IST 2002 Thread-1 Fri Sep 28 17:29:30 IST 2001