क्यों कोई समवर्ती HashSet नहीं समवर्तीHashMap के खिलाफ है


537

HashSet HashMap पर आधारित है।

यदि हम HashSet<E>कार्यान्वयन को देखें, तो सब कुछ प्रबंधित किया जाता है HashMap<E,Object>

<E>की कुंजी के रूप में उपयोग किया जाता है HashMap

और हम जानते हैं कि HashMapयह धागा सुरक्षित नहीं है। यही कारण है कि हम ConcurrentHashMapजावा में हैं।

इसके आधार पर, मुझे भ्रम है कि हमारे पास एक समवर्ती हाशसेट क्यों नहीं है जो कि इसके आधार पर होना चाहिए ConcurrentHashMap?

क्या कुछ और है जो मुझे याद आ रहा है? मुझे Setबहु-थ्रेडेड वातावरण में उपयोग करने की आवश्यकता है।

इसके अलावा, अगर मैं अपना खुद का निर्माण करना चाहता हूं, तो क्या मैं ConcurrentHashSetइसे प्राप्त HashMapकरने ConcurrentHashMapऔर बाकी चीजों को छोड़ने के बजाय इसे प्राप्त कर सकता हूं ?


2
एपीआई को देखने के बाद, अगर मुझे लगता है कि मैं कहूंगा कि यह 2 कारकों से कम लगता है, (1) जावा एपीआई में एक वर्ग बनाने से परहेज करने की जरूरत है हर कम कार्यक्षमता के लिए (2) सुविधा वर्ग प्रदान करना अधिक बार इस्तेमाल किया वस्तुओं। मैं व्यक्तिगत रूप से LinkedHashMap और LinkedHashSet पसंद करता हूं क्योंकि वे आदेश की गारंटी प्रविष्टि आदेश के समान है, एक सेट का उपयोग करने का एकमात्र कारण दोहराव से बचने के लिए है, अक्सर मैं अभी भी प्रविष्टि क्रम बनाए रखना चाहता हूं।
अली

1
@ एली, मैं व्यक्तिगत रूप से लिंक्डहाशपैप और लिंक्डहैश पसंद करता हूं, आप बहुत दूर जाएंगे :)
bestsss

9
थोड़ा पुराना सवाल है, लेकिन जैसा कि यह Google में पहला परिणाम है, यह जानना उपयोगी हो सकता है कि ConcurrentSkipListSet में पहले से ही ConcurrentHashMap का कार्यान्वयन है। देखें docs.oracle.com/javase/7/docs/api/java/util/concurrent/...
इगोर रोड्रिगेज

1
मैंने जावा स्रोत ConcurrentSkipListSetसे ConcurrentSkipListMapजो देखा, वह बनाया गया है , जो लागू होता है ConcurrentNavigableMapऔर ConcurrentMap
तलहा अहमद खान

जवाबों:


580

कोई प्रकार नहीं बनाया गया है ConcurrentHashSetक्योंकि आप हमेशा एक नक्शे से एक सेट प्राप्त कर सकते हैं । चूंकि कई प्रकार के मानचित्र हैं, आप किसी दिए गए नक्शे (या मानचित्र वर्ग) से एक सेट का उत्पादन करने के लिए एक विधि का उपयोग करते हैं।

जावा 8 से पहले, आप एक समवर्ती हैश सेट का उपयोग करके समवर्ती हैश मैप द्वारा समर्थित का उत्पादन करते हैं Collections.newSetFromMap(map)

Java 8 (@Matt द्वारा इंगित) में, आप एक समवर्ती हैश सेट दृश्य के माध्यम से प्राप्त कर सकते हैं ConcurrentHashMap.newKeySet()। यह पुराने की तुलना में थोड़ा सरल है newSetFromMapजिसके लिए आपको खाली मानचित्र ऑब्जेक्ट में पास करना आवश्यक है। लेकिन यह विशिष्ट है ConcurrentHashMap

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


4
क्या मेरा यह कहना सही है कि यदि आप इस तरह से सेट बनाते हैं ConcurrentHashMap, तो आप उन लाभों को खो देते हैं जिनसे आपको लाभ मिलेगा ConcurrentHashMap?
पचेरियर

19
खोने के कोई लाभ नहीं हैं। newSetFromMapका कार्यान्वयन docjar.com/html/api/java/util/Collections.java.html पर लाइन 3841 से शुरू होता है । यह सिर्फ एक आवरण है ....
रे तोल

4
@ और, मुझे लगता है कि "समवर्ती" का उपयोग करने के पीछे की प्रेरणा एपीआई से नहीं बल्कि कार्यान्वयन से होती है - थ्रेड सेफ्टी लेकिन यूनिवर्सल लॉक के बिना - उदाहरण के लिए कई समवर्ती पढ़ता है।
उस्मान संगत

5
ConcurrentSkipList में बहुत सारे (आकार) ओवरहेड हैं और लुकअप धीमे हैं।
ग्रहण किया

3
इस दृष्टिकोण का उपयोग करते समय ध्यान रखें, क्योंकि कुछ तरीकों को सही तरीके से लागू नहीं किया गया है। बस लिंक का पालन करें: Collections.newSetFromMapएक बनाता है SetFromMap। जैसे SetFromMap.removeAllविधि प्रतिनिधि को सौंपती है KeySetView.removeAll, जो विरासत में मिलती है ConcurrentHashMap$CollectionView.removeAll। थोक निकालने वाले तत्वों में यह विधि अत्यधिक अक्षम है। कल्पना removeAll(Collections.emptySet())traverses के सभी तत्वों Mapकुछ भी करने के बिना। एक है ConcurrentHashSetकि corretly कार्यान्वित होने के बाद ज्यादातर मामलों में बेहतर होगा।
बेनेज़


79

अमरूद 15 के साथ आप भी उपयोग कर सकते हैं:

Set s = Sets.newConcurrentHashSet();

12
यह हमेशा एक बुरा सपना है। यदि आपके पास एक सेट या एक नक्शा है जो यह इंगित नहीं करता है कि कुछ सुरक्षित है या नहीं, तो आपको पता चलता है कि सभी प्रकार के खतरे और आपदाएं अनुरक्षण में होती हैं। मैं हमेशा एक प्रकार चाहता हूं जो संग्रह के लिए थ्रेड सुरक्षा को इंगित करता है (या नहीं)।
मार्टिन केर्स्टन

11
विधि का वर्णन वस्तुतः "हैश मैप द्वारा समर्थित थ्रेड-सेफ सेट बनाता है"
किचन

16
जैसा कि मैंने कहा, एक समवर्ती है <E> गायब है। ConcurrentHashMap यह इंगित करने के लिए एक समवर्ती मानचित्र इंटरफ़ेस के साथ आता है। यह एक ही कारण है कि मैं हमेशा इस समवर्ती इंटरफ़ेस को भी जोड़ता हूं।
मार्टिन केर्स्टन

35

रे तोल ने जैसा उल्लेख किया है, यह उतना ही आसान है:

Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();

1
यह जावा 8 की आवश्यकता लगती है। कार्यान्वयन को देखते हुए, यह भी सिर्फ एक आवरण है ConcurrentHashMap
Mygod

20

ऐसा लगता है कि जावा अपने समवर्ती SipListSet के साथ समवर्ती सेट कार्यान्वयन प्रदान करता है । एक स्किपलिस्ट सेट केवल एक विशेष प्रकार का सेट कार्यान्वयन है। यह अभी भी Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet इंटरफेस को लागू करता है। यदि आपको केवल सेट इंटरफ़ेस की आवश्यकता है तो यह आपके लिए काम कर सकता है।


12
ध्यान दें कि ConcurrentSkipListSetतत्वों को होना चाहिएComparable
user454322

यदि आपको एक ऐसे सेट से विस्तार करने की आवश्यकता है जो समवर्ती है, तो यहां एकमात्र समाधान है जो काम करेगा।
ndm13

ConcurrentSkipListMap आधार डेटा संरचना के रूप में वृक्ष होने के अनावश्यक प्रदर्शन दंड को जोड़ता है, इसके बजाय हैशटेबल का उपयोग करने के बावजूद, जब आपको छँटाई / नेविगेशन कार्यक्षमता की आवश्यकता नहीं होती है।
अजीत गंगा

ConcurrentSkipListSetजब तक आप एक का उपयोग न करें SortedSet। जोड़ने के लिए या निकालने की तरह एक सामान्य ऑपरेशन एक के लिए O (1) होना चाहिए HashSet, लेकिन a के लिए O (लॉग (n)) SortedSet
बेनेज़

16

जैसा कि इस के द्वारा एक संगामिति सक्षम HashSet प्राप्त करने का सबसे अच्छा तरीका बताया गया हैCollections.synchronizedSet()

Set s = Collections.synchronizedSet(new HashSet(...));

यह मेरे लिए काम करता है और मैंने किसी को भी वास्तव में इसकी ओर इशारा करते नहीं देखा है।

EDIT यह वर्तमान में aproved समाधान की तुलना में कम कुशल है, जैसा कि यूजीन बताते हैं, क्योंकि यह आपके सेट को एक समकालिक सज्जाकार के रूप में लपेटता है, जबकि ConcurrentHashMapवास्तव में निम्न-स्तरीय संगति लागू करता है और यह आपके सेट को ठीक तरह से वापस कर सकता है। तो यह स्पष्ट करने के लिए श्री स्टेपानेनकोव का धन्यवाद।

http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedSet-java.util.Set-


16
synchronizedSetविधि सिर्फ बनाता है डेकोरेटर के तहत Collectionचादर तरीकों कि धागा सुरक्षित तुल्यकालन द्वारा पूरे संग्रह हो सकता है। लेकिन पूरे संग्रह के किसी भी ताले के बिना गैर-अवरुद्ध एल्गोरिदम और "निम्न-स्तरीय" सिंक्रोनाइज़ेशन ConcurrentHashMapका उपयोग करके कार्यान्वित किया जाता है । इसलिए ... से लिपिक प्रदर्शन कारणों से बहु-थ्रेड वातावरण में बदतर है। Collections.synchronized
यूजीन Stepanenkov 19

12

Sets.newSetFromMap(map)एक पाने के लिए आप अमरूद का उपयोग कर सकते हैं । जावा 6 में वह विधि भी हैjava.util.Collections


यह java.utll.Collections में उपलब्ध है और CHM का सेट आमतौर पर एक बुरी चीज है।
bestsss

हाँ, मैंने देखा कि यह जावा 6 में जोड़ा गया है, इसलिए इसे उत्तर में जोड़ दिया
बोजो

मुख्य यह है कि अगर यह थ्रेडसेफ़ है, और मुझे वास्तव में संदेह है।
तलहा अहमद खान

@Talha, यह धागा सुरक्षित है, तथापि थ्रेड सुरक्षा अकेले साधन कुछ भी नहीं
bestsss

कभी-कभी इसका मतलब सब कुछ होता है। जब तक यह एक एल्गोरिथ्म का हिस्सा नहीं है, जो आमतौर पर एक तरह से लागू किया जाता है कि समवर्ती मानचित्रण की आवश्यकता को कम से कम किया जाता है, तो यह एक प्रदर्शन समस्या है।
मार्टिन केर्स्टन

5
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;


public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>{
   private final ConcurrentMap<E, Object> theMap;

   private static final Object dummy = new Object();

   public ConcurrentHashSet(){
      theMap = new ConcurrentHashMap<E, Object>();
   }

   @Override
   public int size() {
      return theMap.size();
   }

   @Override
   public Iterator<E> iterator(){
      return theMap.keySet().iterator();
   }

   @Override
   public boolean isEmpty(){
      return theMap.isEmpty();
   }

   @Override
   public boolean add(final E o){
      return theMap.put(o, ConcurrentHashSet.dummy) == null;
   }

   @Override
   public boolean contains(final Object o){
      return theMap.containsKey(o);
   }

   @Override
   public void clear(){
      theMap.clear();
   }

   @Override
   public boolean remove(final Object o){
      return theMap.remove(o) == ConcurrentHashSet.dummy;
   }

   public boolean addIfAbsent(final E o){
      Object obj = theMap.putIfAbsent(o, ConcurrentHashSet.dummy);
      return obj == null;
   }
}

2
मुझे डमी ऑब्जेक्ट के बजाय बूलियन.ट्र्यू का उपयोग करने का विचार पसंद है। यह थोड़ा अधिक सुरुचिपूर्ण है। नल का उपयोग भी संभव है क्योंकि यह कुंजी सेट में उपलब्ध होगा भले ही नल से मैप किया गया हो।
मार्टिन केर्स्टन

2
@MartinKersten fyi, ConcurrentHashMap शून्य मानों की अनुमति नहीं देता है
लॉरी लेहटिनन

2

क्यों न करें: CopyOnWriteArraySet java.util.concurrent से?


6
क्योंकि CopyOnWriteArraySet किसी भी राज्य म्यूटेशन पर पूरे संग्रह की प्रतिलिपि बनाता है, जो हमेशा प्रदर्शन प्रभाव के कारण नहीं चाहता है। इसे केवल विशेष मामलों में काम करने के लिए डिज़ाइन किया गया है।
बोनशी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.