2012-08-22 47 views
5

मेरे पास एक सिंक्रनाइज़ किया गया मानचित्र है (Collections.synchronizedMap() के माध्यम से) जिसे थ्रेड ए थ्रेड बी द्वारा पढ़ और अपडेट किया जाता है, केवल Map.keySet() (केवल पढ़ने के लिए) के माध्यम से मानचित्र तक पहुंचता है।एक आर/डब्ल्यू थ्रेड और एक केवल पढ़ने के लिए थ्रेड के बीच मानचित्र सिंक्रनाइज़ करने के लिए कैसे?

मुझे इसे कैसे सिंक्रनाइज़ करना चाहिए? docs say कि keySet() (संग्रह के लिए सिंक्रनाइज़ किए गए मैप) "सिंक्रनाइज़ ब्लॉक में नहीं होना चाहिए"। मैं एक सिंक्रनाइज़ ब्लॉक के भीतर थ्रेड ए को पढ़/लिखने का उपयोग कर सकता हूं, लेकिन क्या यह भी आवश्यक है?

मुझे लगता है कि यह और भी, एक तुल्यकालन मानचित्र, या एक सिंक्रनाइज़ ब्लॉक का उपयोग करने के अगर Map.keySet सिंक्रनाइज़ किए जाने (ऊपर डॉक्स लिंक के अनुसार) की जरूरत नहीं है मेरे लिए अजीब लगता है ...

अद्यतन: मुझे याद आया कि कीसेट को पुन: सिंक्रनाइज़ किया जाना चाहिए, भले ही कुंजीसेट को पुनर्प्राप्त करने के लिए सिंक की आवश्यकता न हो। KeySet को देखने में सक्षम होने के बिना विशेष रूप से रोमांचक नहीं है, इसलिए अंतिम परिणाम = सिंक्रनाइज़ेशन आवश्यक है। इसके बजाय एक ConcurrentHashMap का उपयोग करना।

+0

यह जावा 3 डी के बारे में है? –

+0

@ tuğrulbüyükışık nope। सामान्य जावा समवर्ती प्रश्न। – ericsoco

उत्तर

2

एक सही मायने में पढ़ने/लिखने बनाने बनाम केवल Map आवरण ताला लगा पढ़ने/के लिए, आपको आवरण CollectionssynchronizedMap() के लिए उपयोग करता है पर एक नज़र लेने के लिए और एक ReentrantReadWriteLock साथ synchronized बयानों के सभी जगह ले सकता है। यह काम का एक अच्छा सा है। इसके बजाय, आपको ConcurrentHashMap का उपयोग करने के लिए स्विच करने पर विचार करना चाहिए जो कि सभी सही चीजें करता है।

keySet() के संदर्भ में, यह है क्योंकि यह पहले से ही Collections.synchronizedMap() द्वारा synchronized किया जा रहा है एक synchronized ब्लॉक में होने की जरूरत नहीं है। जावाडॉक्स सिर्फ यह इंगित कर रहा है कि यदि आप मानचित्र के माध्यम से पुनरावृत्ति कर रहे हैं, तो आपको उस पर सिंक्रनाइज़ करने की आवश्यकता है क्योंकि आप कई संचालन कर रहे हैं, लेकिन आपको keySet() प्राप्त होने पर सिंक्रनाइज़ करने की आवश्यकता नहीं है जो SynchronizedSet कक्षा में लपेटा गया है अपने स्वयं के सिंक्रनाइज़ेशन करता है।

आखिरकार, आपका प्रश्न यह प्रतीत होता है कि अगर आप इसे पढ़ रहे हैं तो आपको कुछ सिंक्रनाइज़ करने की आवश्यकता नहीं है। आपको याद रखना होगा कि सिंक्रनाइज़ेशन न केवल दौड़ की स्थितियों के खिलाफ सुरक्षा करता है बल्कि यह भी सुनिश्चित करता है कि डेटा प्रत्येक प्रोसेसर द्वारा सही ढंग से साझा किया जाता है। भले ही आप Map को केवल पढ़ने के लिए एक्सेस कर रहे हों, फिर भी यदि आप कोई अन्य थ्रेड इसे अपडेट कर रहे हैं तो आपको अभी भी सिंक्रनाइज़ करने की आवश्यकता है।

+1

मुझे लगता है कि मैं जानता हूं कि आप क्या कहने की कोशिश कर रहे हैं, लेकिन 'keySet()' * * "मैप' में कुंजी की प्रति नहीं है" (यह एक लाइव व्यू है), और यह नहीं होना चाहिए सिंक्रनाइज़ ब्लॉक में होना चाहिए। यदि यह वास्तव में एक प्रतिलिपि थी और आपने इसे सिंक्रनाइज़ किए गए ब्लॉक में नहीं प्राप्त किया था, तो आपका पुनरावृत्ति खराब डेटा से अधिक हो सकता है। यह सुनिश्चित करने के लिए कि यह ताजा था, आपको सिंक्रनाइज़ेशन में 'कीसेट()' विधि शामिल करना होगा। ConcurrentHashMap सुझाव के लिए –

+0

+1, मैं इसे देख लूंगा। – ericsoco

+0

मुझे पता था कि यह आम तौर पर @ मार्क था लेकिन मैंने कोड को नहीं देखा। अब जब मैं देखता हूं कि यह इसे 'सिंक्रनाइज़सेटसेट' में लपेटता है। मैं अपना जवाब बदल दूंगा। धन्यवाद। – Gray

2

डॉक्स आप कह रहे हैं कैसे ठीक नक्शे पर पुनरावृत्ति इस मामले में, बहु-चरण संचालन परमाणु होने की जरूरत है कि सिंक्रनाइज़ करने के लिए:

Map m = Collections.synchronizedMap(new HashMap()); 
     ... 
Set s = m.keySet(); // Needn't be in synchronized block 
     ... 
synchronized(m) { // Synchronizing on m, not s! 
    Iterator i = s.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

नोट कैसे वास्तविक यात्रा एक तुल्यकालन में होना चाहिए ब्लॉक। दस्तावेज़ सिर्फ यह कह रहे हैं कि प्राप्त करने से कोई फर्क नहीं पड़ता keySet() सिंक्रनाइज़ ब्लॉक में है, क्योंकि यह Map का लाइव व्यू है। यदि नक्शे में कुंजियां प्राप्त होने वाले कुंजी सेट के संदर्भ में और सिंक्रनाइज़ किए गए ब्लॉक की शुरुआत के बीच बदलती हैं, तो कुंजी सेट उन परिवर्तनों को प्रतिबिंबित करेगा।

और वैसे, आपके द्वारा उद्धृत दस्तावेज़ केवल MapCollections.synchronizedMap द्वारा लौटाए गए हैं। बयान आवश्यक नहीं है सभी Map एस पर लागू होता है।

+0

बहुत अच्छा मुद्दा, मुझे याद आया कि कीसेट के पुनरावृत्ति को सिंक्रनाइज़ किया जाना चाहिए। – ericsoco

2

दस्तावेज़ सही हैं। Collections.synchronizedMap() से लौटाया गया मानचित्र मूल Map पर भेजे गए सभी कॉल के आसपास सिंक्रनाइज़ किया जाएगा।हालांकि, keySet() द्वारा दिए गए सेट इम्प्ले में एक ही संपत्ति नहीं है, इसलिए आपको यह सुनिश्चित करना होगा कि यह उसी लॉक के नीचे पढ़ा जाए।

इससे समन्वयन के बिना, कोई गारंटी नहीं है कि धागा बी कभी थ्रेड ए द्वारा किए गए किसी भी अद्यतन

आप ConcurrentHashMap जांच करने के लिए चाहते हो सकता है देखेंगे। यह वास्तव में इस उपयोग के मामले के लिए उपयोगी अर्थशास्त्र प्रदान करता है। सीएचएम (like keySet()) में एक संग्रह दृश्य पर इटरेटिंग उपयोगी समवर्ती व्यवहार ("कमजोर संगत" iterators) देता है। आप पुनरावृत्ति पर संग्रह की स्थिति से सभी चाबियों को पार करेंगे और इटरेटर बनने के बाद आप परिवर्तन देख सकते हैं या नहीं देख सकते हैं।