यह एक समस्या है जिसे मैंने एक उत्तर भी देखा। विधि putIfAbsent
वास्तव में अतिरिक्त ऑब्जेक्ट निर्माण समस्या को हल नहीं करती है, यह केवल यह सुनिश्चित करती है कि उनमें से एक ऑब्जेक्ट किसी अन्य को प्रतिस्थापित नहीं करता है। लेकिन धागे के बीच दौड़ की स्थिति कई ऑब्जेक्ट त्वरण का कारण बन सकती है। मुझे इस समस्या के लिए 3 समाधान मिल सकते हैं (और मैं वरीयता के इस क्रम का पालन करता हूं):
1- यदि आप जावा 8 पर हैं, तो इसे प्राप्त करने का सबसे अच्छा तरीका शायद ConcurrentMap
की विधि है। आपको बस इसे एक गणना समारोह देने की आवश्यकता है जिसे समकालिक रूप से निष्पादित किया जाएगा (कम से कम ConcurrentHashMap
कार्यान्वयन के लिए)। उदाहरण:
private final ConcurrentMap<String, List<String>> entries =
new ConcurrentHashMap<String, List<String>>();
public void method1(String key, String value) {
entries.computeIfAbsent(key, s -> new ArrayList<String>())
.add(value);
}
यह ConcurrentHashMap.computeIfAbsent
की जावाडोक से है:
निर्दिष्ट कुंजी पहले से ही एक मूल्य के साथ संबद्ध नहीं है, तो प्रयास करता दिया मानचित्रण समारोह का उपयोग कर अपने मूल्य की गणना करने के लिए और इसे में प्रवेश करती है इस मानचित्र में शून्य तक। संपूर्ण विधि आमंत्रण परमाणु रूप से किया जाता है, इसलिए कार्य प्रति कुंजी एक बार में लागू होता है। कुछ अन्य धागे द्वारा इस मानचित्र पर अद्यतन संचालन का प्रयास हो सकता है जबकि गणना प्रगति पर है, इसलिए गणना छोटी और सरल होनी चाहिए, और इस मानचित्र को के किसी भी अन्य मैपिंग को अपडेट करने का प्रयास नहीं करना चाहिए।
2- आप जावा 8 उपयोग नहीं कर सकते हैं, तो आप उपयोग कर सकते हैं Guava
के LoadingCache
, जो धागे की सुरक्षित है। आप इसे एक लोड फ़ंक्शन परिभाषित करते हैं (जैसे ऊपर compute
फ़ंक्शन), और आप सुनिश्चित हो सकते हैं कि इसे समकालिक रूप से समझा जाएगा। उदाहरण:
private final LoadingCache<String, List<String>> entries = CacheBuilder.newBuilder()
.build(new CacheLoader<String, List<String>>() {
@Override
public List<String> load(String s) throws Exception {
return new ArrayList<String>();
}
});
public void method2(String key, String value) {
entries.getUnchecked(key).add(value);
}
3- आप या तो अमरूद उपयोग नहीं कर सकते हैं, तो आप मैन्युअल रूप से कभी सिंक्रनाइज़ और एक की दोबारा जांच कर ताला कर सकते हैं। उदाहरण:
private final ConcurrentMap<String, List<String>> entries =
new ConcurrentHashMap<String, List<String>>();
public void method3(String key, String value) {
List<String> existing = entries.get(key);
if (existing != null) {
existing.add(value);
} else {
synchronized (entries) {
List<String> existingSynchronized = entries.get(key);
if (existingSynchronized != null) {
existingSynchronized.add(value);
} else {
List<String> newList = new ArrayList<>();
newList.add(value);
entries.put(key, newList);
}
}
}
}
मैं उन सभी 3 तरीकों में से एक उदाहरण दिया गया बनाया है और इसके अलावा, गैर सिंक्रनाइज़ विधि है, जिसमें अतिरिक्त ऑब्जेक्ट निर्माण का कारण बनता है: http://pastebin.com/qZ4DUjTr
अतिरिक्त वस्तुओं के बारे में चिंता मत करो जब तक कि वहाँ एक बेंचमार्क है। अल्पकालिक ऑब्जेक्ट आवंटन/जीसी आधुनिक जेवीएम में सस्ते सस्ते सस्ते हैं। (मुझे लगता है कि "कुछ" "कोई नहीं" से अधिक है, लेकिन आधुनिक जेवीएम को सामान्य रूप से इसमें कोई समस्या नहीं है।) किसी भी मामले में, अभी भी एक दिलचस्प सवाल है क्योंकि यह उम्मीद है कि यह कुछ दिलचस्प दृष्टिकोण प्रदान करेगा। "आवंटन" आवंटन और जावा में थोड़ा अजीब है, और इस प्रकार बंद होने की कमी या "नाम से गुजरने" की कमी के कारण आम नहीं है।(बेनामी कक्षाएं उस सेक्सी नहीं हैं और आम तौर पर 'putIf..'' के लिए एक समान इंटरफ़ेस के साथ-साथ अधिभार की आवश्यकता होती है)। –
दो साल से अधिक और अभी भी एक महान सवाल है। मैं सचमुच चाहता हूं कि जावा 1.8 ने डिफ़ॉल्ट ऑब्जेक्ट के आलसी तत्कालता के लिए 'putIfAbsent (के कुंजी, प्रदायक मान)' जैसे कुछ जोड़ा होगा। यह निश्चित रूप से धाराओं एपीआई के लिए 'ConcurrentMap' इंटरफ़ेस पर अन्य समर्थन को फिर से लगाया गया है। –
@sparc_spread Java 1.8 ने 'computeIfAbsent (के कुंजी, फ़ंक्शन मैपिंग फ़ंक्शन)' विधि 'और' ConcurrentMap' 'विधि को जोड़ा जो आपको डिफ़ॉल्ट ऑब्जेक्ट के आलसी त्वरण के लिए करना चाहिए। –
Peter