2008-10-16 14 views
7

एक्सेस किए जा रहे मैं एक सूची वस्तु से अधिक थ्रेड द्वारा पहुँचा जा रहा है। ज्यादातर एक धागा है, और कुछ स्थितियों में दो धागे, जो सूची अद्यतन करते हैं। संसाधित किए जा रहे उपयोगकर्ता अनुरोधों की संख्या के आधार पर, एक से पांच धागे हैं जो इस सूची से पढ़ सकते हैं। सूची निष्पादित करने के कार्यों की कतार नहीं है, यह डोमेन ऑब्जेक्ट्स की एक सूची है जिसे पुनर्प्राप्त और अद्यतन किया जा रहा है।
प्रयोग सिंक्रनाइज़ ब्लॉक
प्रयोग सामान्य लॉक (यानी पढ़ने और लिखने ऑप्स का हिस्सा ही लॉक)
प्रयोग ReadWriteLock:बेस्ट दृष्टिकोण एक सूची के लिए जावा 6 में उपयोग करने के लिए समवर्ती

अब इस सूची धागा सुरक्षित करने के लिए उपयोग करने के लिए कई तरीके हैं
प्रयोग नया ConcurrentBLABLBA संग्रह वर्गों में से एक

मेरा प्रश्न:
क्या उपयोग करने के लिए इष्टतम दृष्टिकोण, यह देखते हुए है कि cricital वर्गों आमतौर पर आपरेशन का एक बहुत (ज्यादातर सिर्फ जोड़ने/हटाने के/डालने या सूची से तत्वों हो रही) शामिल नहीं है?
क्या आप ऊपर सूचीबद्ध नहीं, एक और दृष्टिकोण की सिफारिश कर सकते हैं?

कुछ constrains
-optimal प्रदर्शन महत्वपूर्ण है, स्मृति उपयोग इतना नहीं
-यह एक आदेश दिया सूची (वर्तमान में एक ArrayList पर सिंक्रनाइज़ किया जा रहा), होना चाहिए, हालांकि नहीं एक क्रमबद्ध सूची (यानी का प्रयोग कर नहीं तुलनात्मक या तुलनात्मक, लेकिन सम्मिलन आदेश के अनुसार)
- सूची बड़ी होगी, जिसमें 100000 डोमेन ऑब्जेक्ट्स शामिल हैं, इस प्रकार CopyOnWriteArrayList की तरह कुछ उपयोग नहीं किया जा सकता है
- लिखने/अपडेट क्रिटिकल अनुभाग आमतौर पर बहुत तेज़ होते हैं, सरल जोड़ते हैं/हटाएं/डालें या बदलें (सेट)
पढ़ संचालन मुख्य रूप से एक elementAt (इंडेक्स) करना होगा समय के सबसे अधिक फोन -इस, हालांकि कुछ पढ़ने के संचालन एक द्विआधारी खोज, या indexOf (तत्व) कर सकता
-नहीं सूची पर सीधा यात्रा हालांकि आपरेशन की तरह किया जाता है, indexOf (..) सूची पार किए जाने

उत्तर

3

आप एक अनुक्रमिक सूची का उपयोग किया है? यदि नक्शा-प्रकार की संरचना अधिक उपयुक्त है, तो आप ConcurrentHashMap का उपयोग कर सकते हैं। एक सूची के साथ, ReadWriteLock शायद सबसे प्रभावी तरीका है।

संपादित प्रतिबिंबित करने के लिए ओ पी के संपादित करें: प्रविष्टि के आदेश पर द्विआधारी खोज? क्या आप एक टाइमस्टैम्प स्टोर करते हैं और तुलना के लिए अपनी बाइनरी खोज में इसका उपयोग करते हैं? यदि ऐसा है, तो आप टाइमस्टैम्प को कुंजी के रूप में और ConcurrentSkipListMap कंटेनर के रूप में उपयोग करने में सक्षम हो सकते हैं (जो कुंजी ऑर्डर बनाए रखता है)।

+0

मुझे ConcurrentSkipListMap विचार पसंद है। 90% समय में सूची को कुछ टाइमस्टैम्प (प्रत्येक डोमेन ऑब्जेक्ट की आईडी का हिस्सा) के अनुसार क्रमबद्ध किया जाता है, इसलिए शायद इसके लिए अनुकूलन करना उचित है। अभी भी अन्य 10% के बारे में सोचेंगे। –

1

पढ़ने धागे क्या कर रहे हो? यदि वे सूची में पुनरावृत्त कर रहे हैं, तो आपको वास्तव में यह सुनिश्चित करने की ज़रूरत है कि पूरे पुनरावृत्ति प्रक्रिया के दौरान कोई भी सूची को छूता है, अन्यथा आपको बहुत ही अजीब परिणाम मिल सकते हैं।

यदि आप निश्चित रूप से परिभाषित कर सकते हैं कि आपको कौन सी शब्दावली की आवश्यकता है, तो समस्या को हल करना संभव होना चाहिए - लेकिन आपको अच्छी तरह से पता चल जाएगा कि आपको इसे अपने स्वयं के संग्रह प्रकार को सही तरीके से और कुशलता से लिखने की आवश्यकता है। वैकल्पिक रूप से, CopyOnWriteArrayList अच्छी तरह से पर्याप्त हो सकता है - यदि संभावित रूप से महंगा है। असल में, जितना अधिक आप अपनी आवश्यकताओं को जोड़ सकते हैं, उतना ही अधिक कुशल हो सकता है।

+0

मैंने CopyOnWriteArrayList पर एक नज़र डाली थी, लेकिन यह उपयोग करने के लिए बहुत महंगा होगा। सूची में संभावित रूप से 100000 तत्व हो सकते हैं, और बहुत कुछ अपडेट हो जाता है। –

+2

ठीक है, इस मामले में आपको वास्तव में अपने अर्थशास्त्र को ध्यान से काम करने की आवश्यकता होगी। क्या ये अपडेट आवेषण/हटाए गए हैं, या सिर्फ तत्वों को बदल रहे हैं? अगर वे जोड़ रहे/हटा रहे हैं, तो क्या वे सूची के सिर/पूंछ पर ऐसा कर रहे हैं? (इस मामले में एक लिंक्ड सूची वास्तव में आपकी मदद कर सकती है।) –

1

यदि इस समस्या के लिए एक posible के समाधान है, लेकिन मैं नहीं जानता कि ... यह मेरे लिए समझ में आता है डेटा की है कि भारी मात्रा में धारण करने के लिए एक डाटाबेस प्रबंधक का उपयोग करें और यह लेन-देन का प्रबंधन करते हैं

+0

डेटा डीबी मैनेजर और एप्ससेवर परत द्वारा सर्वर की तरफ प्रबंधित किया जाता है, लेकिन हमें किसी भी तरह इसे अंतिम उपयोगकर्ता को प्रदर्शित करने की आवश्यकता है।इस सूची का मैनगैमेट क्लाइंट-साइड पर होता है जहां डेटा पुनर्प्राप्त किया जाता है। –

1

मैं करने के लिए डेटाबेस के दूसरे Telcontar's suggestion, क्योंकि वे वास्तव में डेटा के इस पैमाने के प्रबंधन और धागे के बीच बातचीत के लिए डिज़ाइन किए गए हैं, जबकि इन-मेमोरी संग्रह नहीं हैं।

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

एक कैश लिखें जो केवल क्लाइंट पर डेटा के मौजूदा सबसेट को स्टोर करता है। यह क्लाइंट कैश जटिल डेटा मल्टीथ्रेड किए गए संपादन को अपने डेटा पर नहीं करता है; इसके बजाय यह सर्वर के माध्यम से सभी संपादन फ़ीड करता है, और अपडेट के लिए सुनता है। जब सर्वर पर डेटा बदलता है, क्लाइंट बस भूल जाता है और पुराना डेटा भूल जाता है और इसे फिर से लोड करता है। केवल एक नामित थ्रेड को संग्रह को पढ़ने या लिखने की अनुमति है। इस तरह क्लाइंट बस जटिल संपादन की आवश्यकता के बजाय, सर्वर पर होने वाले संपादन को प्रतिबिंबित करता है।

हां, यह काफी जटिल समाधान है। इसके बारे में घटक हैं:

  • डेटा की एक सीमा लोड करने के लिए एक प्रोटोकॉल का कहना है कि आइटम 478712 करने के लिए 478901, बल्कि पूरी बात
  • बदल डेटा
  • एक कैश वर्ग के बारे में अपडेट प्राप्त करने के लिए एक प्रोटोकॉल से जो सर्वर पर उनके ज्ञात इंडेक्स द्वारा आइटम
  • सर्वर के साथ संचारित उस कैश से संबंधित एक थ्रेड संग्रहीत करता है। यह केवल धागा है कि संग्रह में ही लिखता है
  • एक धागा है कि कैश जो कॉलबैक प्रक्रियाओं जब डेटा
  • एक इंटरफेस है कि UI घटक उन्हें डेटा प्राप्त करने के लिए अनुमति देने के लिए लागू है, जब यह लोड किया गया है लिया गया है से संबंधित

पहले वार में इस कैश की हड्डियों कुछ इस तरह दिख सकता है:

class ServerCacheViewThingy { 
    private static final int ACCEPTABLE_SIZE = 500; 
    private int viewStart, viewLength; 
    final Map<Integer, Record> items 
      = new HashMap<Integer, Record>(1000); 
    final ConcurrentLinkedQueue<Callback> callbackQueue 
      = new ConcurrentLinkedQueue<Callback>(); 

    public void getRecords (int start, int length, ViewReciever reciever) { 
     // remember the current view, to prevent records within 
     // this view from being accidentally pruned. 
     viewStart = start; 
     viewLenght = length; 

     // if the selected area is not already loaded, send a request 
     // to load that area 
     if (!rangeLoaded(start, length)) 
      addLoadRequest(start, length); 

     // add the reciever to the queue, so it will be processed 
     // when the data has arrived 
     if (reciever != null) 
      callbackQueue.add(new Callback(start, length, reciever)); 
    } 

    class Callback { 
     int start; 
     int length; 
     ViewReciever reciever; 
     ... 
    } 

    class EditorThread extends Thread { 

     private void prune() { 
      if (items.size() <= ACCEPTABLE_SIZE) 
       return; 
      for (Map.Entry<Integer, Record> entry : items.entrySet()) { 
       int position = entry.key(); 
       // if the position is outside the current view, 
       // remove that item from the cache 
       ... 
      } 
     } 

     private void markDirty (int from) { ... } 

     .... 
    } 

    class CallbackThread extends Thread { 
     public void notifyCallback (Callback callback); 
     private void processCallback (Callback) { 
      readRecords 
     } 
    } 
} 

interface ViewReciever { 
    void recieveData (int viewStart, Record[] records); 
    void recieveTimeout(); 
} 

वहाँ विस्तार आप खुद के लिए में भरने के लिए, स्पष्ट रूप से करना होगा की एक बहुत कुछ है।

import java.util.Collections; 
import java.util.ArrayList; 

ArrayList list = new ArrayList(); 
List syncList = Collections.synchronizedList(list); 

// make sure you only use syncList for your future calls... 

यह एक आसान उपाय है:

+0

आपके उत्तर के लिए धन्यवाद। 100000 तक की चीजें डेटा का "पृष्ठ" है जिसे हम ग्राहक को पुनर्प्राप्त कर रहे हैं। डीबी में अरबों प्रविष्टियां हो सकती हैं। मैं केवल एक धागे के साथ सूची तक पहुंचने पर आपकी सलाह पर गंभीरता से विचार करूंगा। यह निश्चित रूप से चीजों को सरल बना देगा। –

1

आप एक आवरण है कि तुल्यकालन को लागू करता है का उपयोग कर सकते हैं। मैं अधिक जटिल समाधानों का सहारा लेने से पहले यह कोशिश करता हूं।

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