ConcurrentHashMap के भीतर परमाणु इंटेगर में जोड़ना - जावा, मल्टीथ्रेडिंग, concurrency, java.util.concurrent, concurrenthashmap

मेरे पास निम्नलिखित परिभाषित है

private ConcurrentMap<Integer, AtomicInteger>  = new ConcurrentHashMap<Integer, AtomicInteger>();

private void add() {
staffValues.replace(100, staffValues.get(100), new AtomicInteger(staffValues.get(100).addAndGet(200)));
}

परीक्षण के बाद, मुझे जो मूल्य मिल रहा है वह नहीं हैंउम्मीद है, और मुझे लगता है कि यहाँ दौड़ की स्थिति है। क्या किसी को पता है कि प्रतिस्थापन समारोह में कॉल प्राप्त करके इसे थ्रेडसेफ माना जाएगा?

उत्तर:

जवाब के लिए 2 № 1

आपके कोड के साथ कुछ समस्याएं हैं। सबसे बड़ा यह है कि आप "रिटर्न-वैल्यू को अनदेखा कर रहे हैं ConcurrentHashMap.replace: यदि प्रतिस्थापन नहीं होता है (एक अन्य थ्रेड के कारण समानांतर में प्रतिस्थापन किया जाता है), तो आप बस आगे बढ़ते हैं जैसे की यह हुआ। यह मुख्य कारण है कि आपको गलत परिणाम मिल रहे हैं।

मुझे यह भी लगता है कि यह एक म्यूटेट करने के लिए एक डिजाइन गलती है AtomicInteger और फिर तुरंत इसे एक अलग से प्रतिस्थापित करें AtomicInteger; यहां तक ​​कि यदि आप यह काम कर सकते हैं, तो इसके लिए कोई कारण नहीं है।

अंत में, मुझे नहीं लगता कि आपको कॉल करना चाहिए staffValues.get(100) दो बार। मुझे नहीं लगता कि वर्तमान कोड में एक बग का कारण बनता है - आपकी शुद्धता केवल दूसरे कॉल पर निर्भर करती है जो पहले से "नया" परिणाम लौटाती है, जो मुझे लगता है है वास्तव में गारंटीकृत ConcurrentHashMap - लेकिन यह नाजुक और सूक्ष्म और भ्रमित है। आम तौर पर, जब आप कॉल करते हैं ConcurrentHashMap.replace, इसका तीसरा तर्क कुछ ऐसा होना चाहिए जिसे आपने दूसरे का उपयोग करके गणना की हो।

कुल मिलाकर, आप या तो उपयोग करके अपने कोड को सरल बना सकते हैं AtomicInteger:

private ConcurrentMap<Integer, Integer> staffValues = new ConcurrentHashMap<>();

private void add() {
final Integer prevValue = staffValues.get(100);
staffValues.replace(100, prevValue, prevValue + 200);
}

या उपयोग नहीं कर रहा है replace (और शायद यहां तक ​​कि नहीं ConcurrentMap, इस बात पर निर्भर करता है कि आप इस मानचित्र को कैसे छू रहे हैं):

private Map<Integer, AtomicInteger> staffValues = new HashMap<>();

private void add() {
staffValues.get(100).addAndGet(200);
}

उत्तर № 2 के लिए 1

इस तरह की स्थितियों को संभालने का एक अच्छा तरीका है computeIfAbsent विधि (नहीं compute विधि कि @ the8472 अनुशंसा करता है)

The computeIfAbsent 2 तर्क स्वीकार करता है, कुंजी, और एक Function<K, V> जिसे केवल तभी कॉल किया जाएगा यदि वह मौजूदा मान अनुपलब्ध है ।चूंकि एक AtomicInteger थ्रेड को एकाधिक थ्रेड से वृद्धि करने के लिए सुरक्षित है, आप इसे आसानी से निंन तरीके से उपयोग कर सकते हैं:

staffValues.computeIfAbsent(100, k -> new AtomicInteger(0)).addAndGet(200);

जवाब के लिए 0 № 3

तुम डॉन "टी का उपयोग करने की आवश्यकता replace(). AtomicInteger एक परिवर्तनशील मूल्य है कि जब भी आप इसे बढ़ाना चाहते है प्रतिस्थापित करने की आवश्यकता नहीं है ।वास्तव में addAndGet पहले से ही यह जगह में वृद्धि ।

इसके बजाय उपयोग compute एक डिफ़ॉल्ट (संभवतः 0) के नक्शे में जब कोई भी मौजूद है और अंयथा पूर्व मौजूदा मूल्य और वृद्धि है कि प्राप्त मूल्य डाल दिया ।

यदि, दूसरी ओर, आप अपरिवर्तनीय मूल्यों का उपयोग करना चाहते है डाल Integer के बजाय इंस्टेंसेस AtomicInteger नक्शे में और उंहें परमाणु गणना के साथ अद्यतन करें//


संबंधित सवाल
सबसे लोकप्रिय