12

यह एक डुप्लिकेट प्रश्न हो सकता है, लेकिन मुझे कोड के इस हिस्से को समरूपता के बारे में एक पुस्तक में मिला है। यह कहा जाता है कि धागे की सुरक्षा के लिए:जावा ConcurrentHashMap क्रिया परमाणुता

ConcurrentHashMap<String, Integer> counts = new ...; 

private void countThing(String thing) { 
    while (true) { 
     Integer currentCount = counts.get(thing); 
     if (currentCount == null) { 
      if (counts.putIfAbsent(thing, 1) == null) 
       break; 
     } else if (counts.replace(thing, currentCount, currentCount + 1)) { 
      break; 
     } 
    } 
} 

मेरे से (संगामिति शुरुआती ') की दृष्टि, धागा t1 और थ्रेड t2 दोनों currentCount = 1 पढ़ सकते हैं। फिर दोनों धागे नक्शे के मूल्य को 2 में बदल सकते हैं। क्या कोई मुझे बता सकता है कि कोड ठीक है या नहीं?

उत्तर

11

चाल यह है कि replace(K key, V oldValue, V newValue) आपके लिए परमाणुता प्रदान करता है। the docs (जोर मेरा) से:

एक महत्वपूर्ण केवल के लिए प्रवेश करता है, तो वर्तमान में किसी दिए गए मान पर मैप से बदलता है। ... कार्रवाई परमाणु रूप से किया जाता है।

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

तो, यह नहीं हो सकता है कि replace फ़ंक्शन के भीतर दोनों धागे currentAction == 1 देखें। उनमें से एक इसे 1 के रूप में देखेगा, और इस प्रकार replace पर इसका आविष्कार सच हो जाएगा। दूसरा इसे 2 (पहली कॉल के कारण) के रूप में देखेगा, और इस प्रकार — झूठी वापसी करेगा और इस बार फिर से प्रयास करने के लिए लूप वापस currentAction == 2 के नए मान के साथ देखेंगे।

बेशक, यह हो सकता है कि एक तीसरा थ्रेड इस दौरान 3 से चालू एक्शन को अपडेट कर दिया गया हो, इस मामले में कि दूसरा धागा तब तक कोशिश कर रहा है जब तक कि यह भाग्यशाली न हो कि कोई भी इसके आगे कूद न सके।

+0

आपको बहुत बहुत धन्यवाद का उपयोग करके अपने खुद के पाश लेखन से बच सकते हैं, मुझे लगता है कि मैं अब समझते हैं। :) –

-1

डालकर आप मूल्य को भी बदल सकते हैं।

if (currentCount == null) { 
     counts.put(thing, 2); 
    } 
6

कोई मुझे कृपया समझा सकते हैं कि कोड ठीक है या नहीं?

yshavit के जवाब देने के लिए इसके अलावा, आप compute जो जावा 8. में जोड़ा गया

ConcurrentMap<String, Integer> counts = new ...; 

private void countThing(String thing) { 
    counts.compute(thing, (k, prev) -> prev == null ? 1 : 1 + prev); 
} 
+0

कूल, धन्यवाद! :) –

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