2010-03-24 15 views
5

मैं मल्टी थ्रेडिंग के संबंध में अच्छी प्रतिष्ठा के कारण जोडा का उपयोग कर रहा हूं। यह बहु थ्रेडेड डेट हैंडलिंग कुशल बनाने के लिए बहुत दूर है, उदाहरण के लिए सभी दिनांक/समय/डेटटाइम ऑब्जेक्ट्स अपरिवर्तनीय बनाकर।आंशिक रूप से निर्मित ऑब्जेक्ट/मल्टी थ्रेडिंग

लेकिन यहां एक ऐसी स्थिति है जहां मुझे यकीन नहीं है कि जोडा वास्तव में सही काम कर रहा है या नहीं। यह शायद करता है, लेकिन मुझे एक स्पष्टीकरण देखने में बहुत दिलचस्पी है।

/* org.joda.time.base.AbstractInstant */ 
public String toString() { 
    return ISODateTimeFormat.dateTime().print(this); 
} 

सभी formatters (वे के रूप में अच्छी अपरिवर्तनीय) धागा सुरक्षित हैं, लेकिन क्या फ़ॉर्मेटर-कारखाने के बारे में बताया गया है::

दिनांक समय की एक toString() Joda बुलाया जा रहा है जब निम्नलिखित करता है

private static DateTimeFormatter dt; 

/* org.joda.time.format.ISODateTimeFormat */ 
public static DateTimeFormatter dateTime() { 
    if (dt == null) { 
     dt = new DateTimeFormatterBuilder() 
      .append(date()) 
      .append(tTime()) 
      .toFormatter(); 
    } 
    return dt; 
} 

यह सिंगल थ्रेडेड अनुप्रयोगों में एक आम पैटर्न है लेकिन इसे बहु-प्रसारित वातावरण में त्रुटि-प्रवण माना जाता है। > सबसे खराब स्थिति - अशक्त जांच के दौरान

  • दौड़ हालत: दो वस्तुओं बनाया हो

    मैं निम्नलिखित खतरों को देखते हैं।

कोई समस्या नहीं है, क्योंकि यह पूरी तरह से एक सहायक वस्तु है (सामान्य सिंगलटन पैटर्न की स्थिति के विपरीत), कोई डीटी में सहेजा जाता है, दूसरा खो जाता है और कचरा जल्द या बाद में एकत्र किया जाएगा।

  • से पहले ओर्ब प्रारंभ समाप्त कर दिया गया

स्थिर चर एक आंशिक रूप से निर्माण वस्तु को इंगित कर सकते हैं (मुझे पागल कॉल करने से पहले, इस Wikipedia article में इसी तरह की स्थिति के बारे में पढ़ा।)

तो जोडा कैसे सुनिश्चित करता है कि इस स्थैतिक चर में कोई आंशिक रूप से निर्मित फॉर्मेटर प्रकाशित नहीं होता है?

अपने स्पष्टीकरण के लिए धन्यवाद!

रीटो

उत्तर

4

आपने कहा, कि प्रारूपक केवल पढ़ने के लिए हैं। यदि वे केवल अंतिम फ़ील्ड का उपयोग करते हैं (मैंने एक फॉर्मेटर स्रोत नहीं पढ़ा) तो जावा भाषा विनिर्देश के 3-संस्करण में उन्हें "अंतिम फील्ड सेमेटिक्स" द्वारा पार्टिकल ऑब्जेक्ट सृजन से संरक्षित किया जाता है। मैंने 2-जेएस जेएसएल संस्करण की जांच नहीं की और सुनिश्चित नहीं किया कि अगर इस तरह के initalization उस संस्करण में सही है।

जेएलएस में अध्याय 17.5 और 17.5.1 देखें। मैं संबंध के पहले आवश्यक होने के लिए एक "घटना श्रृंखला" का निर्माण करूंगा।

सबसे पहले, कन्स्ट्रक्टर में कहीं भी फॉर्मेटर में अंतिम क्षेत्र में एक लिखना है। यह लिखना डब्ल्यू है। जब कन्स्ट्रक्टर पूरा हो जाता है, तो "फ्रीज" एक्शन प्लेस लेता है। चलो इसे एफ कहते हैं। बाद में प्रोग्राम ऑर्डर में (कन्स्ट्रक्टर से लौटने के बाद, हो सकता है कि कुछ अन्य तरीकों और फॉरमेटर से लौटें) डीटी क्षेत्र में एक लिखना है। आइए इसे एक नाम दें। यह लिखना (ए) "प्रोग्राम ऑर्डर" (एकल-थ्रेडेड निष्पादन में क्रम) में फ्रीज एक्शन (एफ) के बाद है और इस प्रकार एफ (एचबी (एफ, ए)) से पहले जेएलएस परिभाषा द्वारा होता है। पूhew, प्रारंभिक पूर्ण ... :)

सोमवार, बाद में, किसी अन्य धागे में, कॉल टू डेटटाइम() प्रारूप होता है। उस समय हमें दो पढ़ने की जरूरत है। दो में से पहले फॉर्मेटर ऑब्जेक्ट में अंतिम चर के बारे में पढ़ा जाता है। आइए इसे आर 2 (जेएलएस के साथ संगत होने के लिए) कहते हैं। दोनों में से दूसरा फॉर्मेटर के लिए "यह" का एक पठन है। यह दिनांक फ़ील्ड() विधि को कॉल के दौरान होता है जब डीटी फ़ील्ड पढ़ा जाता है। और चलिए इसे पढ़ा आर 1 कहते हैं। अब हमारे पास क्या है? आर 1 पढ़ें कुछ डीटी को लिखते हैं। मैं मानता हूं कि यह लेखन पिछले पैराग्राफ से एक कार्रवाई थी (केवल एक थ्रेड उस क्षेत्र को लिखा था, केवल सादगी के लिए)। चूंकि आर 1 लिखते हैं, तो एमसी (ए, आर 1) ("मेमोरी चेन" संबंध, पहली खंड परिभाषा) है। वर्तमान धागे ने एक फॉर्मेटर शुरू नहीं किया है, इसे क्रिया आर 2 में फ़ील्ड पढ़ता है और एक्शन आर 1 पर एक फॉर्मेटर के "पता" को देखता है। इस प्रकार, परिभाषा के अनुसार, एक dereferences (आर 1, आर 2) (जेएलएस से एक और कार्रवाई आदेश) है।

हमने फ्रीज, एचबी (डब्ल्यू, एफ) से पहले लिखा है। डीटी, एचबी (एफ, ए) के असाइनमेंट से पहले हमने फ्रीज किया है। हमने डीटी, एमसी (ए, आर 1) से पढ़ा है। और हमारे पास आर 1 और आर 2, डेरेफरेंस (आर 1, आर 2) के बीच एक अव्यवस्था श्रृंखला है। यह सब जेएलएस परिभाषा द्वारा एचबी (डब्ल्यू, आर 2) संबंध से पहले होता है। इसके अलावा, परिभाषा के अनुसार, एचबी (डी, डब्ल्यू) जहां डी वस्तु में अंतिम क्षेत्र के लिए डिफ़ॉल्ट मान का एक लेखन है। इस प्रकार, आर 2 पढ़ना डब्ल्यू नहीं देख सकता है और लिखना आर 2 देखना चाहिए (प्रोग्राम कोड से फ़ील्ड को केवल लिखें)।

वही अप्रत्यक्ष क्षेत्र पहुंच (अंतिम क्षेत्र में संग्रहीत ऑब्जेक्ट का अंतिम क्षेत्र इत्यादि) का क्रम है ...)।

लेकिन यह सब नहीं है! आंशिक रूप से निर्मित वस्तु के लिए कोई पहुंच नहीं है। लेकिन एक और दिलचस्प बग है। किसी भी स्पष्ट synhronization दिनांक की कमी में समय() शून्य वापस आ सकता है। मुझे नहीं लगता कि इस तरह के व्यवहार अभ्यास में देखा जा सकता है, लेकिन जेएलएस 3-rd संस्करण इस तरह के व्यवहार को रोकता नहीं है। विधि में डीटी फ़ील्ड के पहले पढ़ने को किसी अन्य थ्रेड द्वारा प्रारंभिक मान दिखाई दे सकता है, लेकिन डीटी के दूसरे पढ़ने में "डिफॉल्ट मूल्य का लिखना" दिखाई दे सकता है। ऐसा नहीं होता है- इससे पहले कि इसे रोकने के लिए संबंध मौजूद हैं। ऐसा संभव व्यवहार 3-rd संस्करण के लिए विशिष्ट है, दूसरे संस्करण में "मुख्य स्मृति को लिखें"/"मुख्य स्मृति से पढ़ा गया है" जो थ्रेड को वैरिएबल के मानों को समय पर वापस देखने की अनुमति नहीं देता है।

+0

+1। यही एक और कारण है कि जावा समवर्ती मॉडल में अपरिवर्तनीय वस्तुएं 'सरल' हैं। हालांकि, मुझे आपके पिछले पैराग्राफ के बारे में निश्चित नहीं है, जेएलएस 17.4.4 देखें: "प्रत्येक चर में डिफ़ॉल्ट मान (शून्य, झूठी या शून्य) का लिखना सिंक्रनाइज़ करता है-प्रत्येक थ्रेड में पहली क्रिया के साथ"। यह आवश्यक है कि "डिफ़ॉल्ट मान का लेखन" डीटी के पढ़ने से पहले होता है। – irreputable

+0

हां, डिफ़ॉल्ट मान का लेखन डीटी के पढ़ने से पहले है। यह थ्रेड को "कचरा" मान पढ़ने से रोकता है। लेकिन किसी अन्य धागे (जो डीटी क्षेत्र शुरू किया गया) में क्षेत्र का एक लेखन डीटी पढ़ने के साथ एचबी-रिलेशन में नहीं है। इस प्रकार हम किसी भी समय उन दो में से किसी एक को लिख सकते हैं (डिफ़ॉल्ट या थ्रेड से शुरू किया गया था)। एकमात्र समय जब हमें एक डिफ़ॉल्ट प्रारंभिक मान पढ़ना होगा, तो आकस्मिक आवश्यकता जांच है। लेकिन उस समय हम केवल डिफ़ॉल्ट मान के साथ एक ही पठन करते हैं और अगले पुनरावृत्ति पर कहते हैं कि वह धागा किसी ऑब्जेक्ट को डीटी (केवल विधि में पढ़ने के लिए) लिखता है। – maxkar

-1

IMO सबसे खराब स्थिति नहीं दो वस्तुओं बनाया है, लेकिन कई हो रही (कई के रूप में वहाँ के रूप में धागे dateTime() बुला, सटीक होना करने के लिए कर रहे हैं) है। चूंकि dateTime() सिंक्रनाइज़ नहीं है और dt न तो अंतिम और न ही अस्थिर है, एक थ्रेड में इसके मूल्य में परिवर्तन अन्य धागे के लिए दृश्यमान होने की गारंटी नहीं है। तो एक धागे के बाद भी dt शुरू हुआ, फिर भी किसी अन्य धागे को संदर्भ के रूप में संदर्भ दिखाई दे सकता है, इस प्रकार खुशी से नई वस्तुओं को बनाते हैं।

इसके अलावा, जैसा कि दूसरों द्वारा समझाया गया है, आंशिक रूप से निर्मित वस्तु dateTime() द्वारा प्रकाशित नहीं की जा सकती है। न तो आंशिक रूप से बदला जा सकता है (= dangling) संदर्भ, क्योंकि संदर्भ मान अद्यतन परमाणु होने की गारंटी है।

0

यह एक गैर-जवाब का एक सा है, लेकिन

के लिए सरल व्याख्या तो Joda सुनिश्चित करता है कि आंशिक रूप से बनाई गई फ़ॉर्मेटर इस स्थैतिक चर में प्रकाशित होता है ना?

शायद यह हो सकता है कि वे कुछ भी सुनिश्चित न करें, और या तो डेवलपर्स को यह नहीं पता था कि यह एक बग हो सकता है या महसूस किया कि यह सिंक्रनाइज़ करने के लायक नहीं था।

0

2007 में जोडा मेलिंग सूची पर asked a similar question, हालांकि मुझे निर्णायक होने का जवाब नहीं मिला और परिणामस्वरूप, मैंने बेहतर या बदतर के परिणामस्वरूप जोडा समय से परहेज किया।

जावा भाषा स्पेक का संस्करण 3 गारंटी देता है कि ऑब्जेक्ट संदर्भ अद्यतन परमाणु हैं, भले ही वे 32-बिट या 64-बिट हों।यह ऊपर उल्लिखित तर्कों के साथ संयुक्त है, जोडा कोड थ्रेड-सुरक्षित आईएमओ बनाता है (देखें java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7)

आईआईआरसी, संस्करण 2 का जेएलएस में ऑब्जेक्ट रेफरेंस के बारे में एक ही स्पष्ट स्पष्टीकरण शामिल नहीं था, यानी केवल 32-बिट रेफरी परमाणु की गारंटी थी, इसलिए यदि आप 64 बिट जेवीएम का उपयोग कर रहे थे तो कोई गारंटी नहीं थी कि यह काम करेगा। उस समय मैं जावा 1.4 का उपयोग कर रहा था, जो प्री-डेटेड जेएलएस वी 3 था।

संबंधित मुद्दे