जावाडोक स्पष्ट रूप से कारण बताते हैं:
कुछ अन्य धागे से इस नक्शे पर प्रयास किया अद्यतन संचालन हो सकता है अवरुद्ध जबकि गणना प्रगति में है, इसलिए गणना छोटे और सरल होना चाहिए , और इस मानचित्र को के किसी भी अन्य मैपिंग को अपडेट करने का प्रयास नहीं करना चाहिए।
आप ताला लगा के रूप में यह HashTable
जैसे पुराने धागा सुरक्षित मानचित्र कक्षाओं के लिए मामला है किया जा रहा बिना भूल जाते हैं कि ConcurrentHashMap
एक धागा सुरक्षित मानचित्र का उपयोग करने का एक तरीका प्रदान बनाया गया है नहीं किया है।
जब मानचित्र पर कोई संशोधन होता है, तो यह केवल संबंधित मैपिंग को ताला लगाता है, न कि संपूर्ण मानचित्र।
ConcurrentHashMap
अद्यतन के लिए retrievals की पूर्ण संगामिति और उच्च उम्मीद संगामिति समर्थन एक हैश तालिका है।
computeIfAbsent()
एक नई पद्धति जावा में जोड़ा है 8.
तो बुरी तरह से इस्तेमाल किया है, वह यह है कि, computeIfAbsent()
के शरीर कि पहले से ही कुंजी विधि को पास किए जाने की मैपिंग ताले में, आप एक और लॉक कुंजी है, तो आप उस पथ में प्रवेश करें जहां आप ConcurrentHashMap
के उद्देश्य को हरा सकते हैं, अंततः आप दो मैपिंग लॉक कर देंगे।
अगर आप computeIfAbsent()
के अंदर और मैपिंग लॉक करते हैं तो समस्या की कल्पना करें और यह विधि बिल्कुल कम नहीं है। मानचित्र पर Concurrency पहुंच धीमा हो जाएगा।
तो computeIfAbsent()
का जावाडोक ConcurrentHashMap
के सिद्धांतों को याद करके इस संभावित मुद्दे पर जोर देता है: इसे सरल और तेज़ रखें।
यहां समस्या का वर्णन करने वाला उदाहरण कोड है।
मान लें कि हमारे पास ConcurrentHashMap<Integer, String>
का उदाहरण है।
हम दो धागे कि इसका इस्तेमाल शुरू कर देंगे:
- पहले धागा:
thread1
कि कुंजी 1
- दूसरे धागे से
computeIfAbsent()
का आह्वान: thread2
कि कुंजी 2
साथ
computeIfAbsent()
का आह्वान
thread1
एक तेज़ पर्याप्त कार्य निष्पादित करता है लेकिन यह सलाह का पालन नहीं करता है computeIfAbsent()
javadoc: यह computeIfAbsent()
में कुंजी 2
अपडेट करता है, यह एक और मैपिंग है जिसका उपयोग विधि के वर्तमान संदर्भ में किया जाता है (जो कि 1
है)।
thread2
एक लंबे समय तक पर्याप्त कार्य निष्पादित करता है। यह javadoc की सलाह के बाद 2
कुंजी computeIfAbsent()
के साथ आमंत्रित करता है: यह इसके कार्यान्वयन में किसी भी अन्य मानचित्रण को अद्यतन नहीं करता है।
लंबे कार्य को अनुकरण करने के लिए, हम पैरामीटर के रूप में 5000
के साथ Thread.sleep()
विधि का उपयोग कर सकते हैं।
इस विशिष्ट स्थिति के लिए, यदि thread1
से पहले thread2
शुरू होता है, thread1
में map.put(2, someValue);
के आह्वान करते हुए thread2
अवरुद्ध हो जाएगा computeIfAbsent()
कि कुंजी 2
की मैपिंग ताले की न हो।
अंत में, हम एक ConcurrentHashMap
उदाहरण है कि ब्लॉक प्रमुख 2
5 दौरान सेकंड के मानचित्रण, जबकि computeIfAbsent()
कुंजी 1
के मानचित्रण के साथ शुरू हो जाती है मिलता है।
यह भ्रामक, प्रभावी नहीं है और यह ConcurrentHashMap
इरादा और computeIfAbsent()
वर्णन जो इरादा मौजूदा कुंजी के लिए मूल्य की गणना कर रहा है के खिलाफ जाता है:
यदि निर्दिष्ट कुंजी पहले से ही एक मूल्य के साथ संबद्ध नहीं है, प्रयास दिया मानचित्रण समारोह का उपयोग कर अपने मूल्य की गणना और यह में प्रवेश करती है जब तक कि इस नक्शे को अशक्त में करने के लिए
नमूना कोड:
import java.util.concurrent.ConcurrentHashMap;
public class BlockingCallOfComputeIfAbsentWithConcurrentHashMap {
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
Thread thread1 = new Thread() {
@Override
public void run() {
map.computeIfAbsent(1, e -> {
String valueForKey2 = map.get(2);
System.out.println("thread1 : get() returns with value for key 2 = " + valueForKey2);
String oldValueForKey2 = map.put(2, "newValue");
System.out.println("thread1 : after put() returns, previous value for key 2 = " + oldValueForKey2);
return map.get(2);
});
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
map.computeIfAbsent(2, e -> {
try {
Thread.sleep(5000);
} catch (Exception e1) {
e1.printStackTrace();
}
String value = "valueSetByThread2";
System.out.println("thread2 : computeIfAbsent() returns with value for key 2 = " + value);
return value;
});
}
};
thread2.start();
Thread.sleep(1000);
thread1.start();
}
}
उत्पादन के रूप में हम हमेशा मिलती है:
thread1: (मिल) के लिए कुंजी 2 = अशक्त
thread2 मूल्य के साथ प्रस्तुत करती है: computeIfAbsent() के लिए कुंजी 2 = मूल्य के साथ रिटर्न valueSetByThread2
थ्रेड 1: डालने के बाद() रिटर्न, कुंजी 2 = वैल्यूसेटबेट थ्रेड 2
यह writt है एन तेजी से ConcurrentHashMap
पर पढ़ता अवरुद्ध नहीं कर रहे:
thread1: (मिल) के लिए कुंजी 2 = अशक्त
मूल्य के साथ देता है, लेकिन यह:
thread1: पुट के बाद () रिटर्न, कुंजी 2 = वैल्यूसेटबेट थ्रेड 2
केवल आउटपुट केवल तभी होता है जब थ्रेड 2 लौटाया जाता है computeIfAbsent()
की।
इस तरह की एक कल्पना बहुत सावधानी से पढ़ी जानी चाहिए। "प्रयास नहीं करना चाहिए" शब्द इंगित करते हैं कि यदि आप नियम का पालन नहीं करते हैं तो शायद आप कहीं और तोड़ सकते हैं। लेकिन एंडी की तुलना में मैं हमेशा वास्तव में दिलचस्पी लेता हूं कि ऐसे प्रतिबंध क्यों लगाए जाते हैं। –