2013-08-20 6 views
6

मेरे पास उन कार्यों का कतार है जो ऑब्जेक्ट्स के संग्रह पर काम करते हैं (मान लीजिए कि ऑब्जेक्ट्स एड्रेस बुक में प्रविष्टियां हैं, उदाहरण के लिए)।कुछ लेनदेन के आदेश के मामले में मैं कतार उपभोक्ता को कैसे समूहीकृत कर सकता हूं?

एक उदाहरण कार्य "जोए का फोन नंबर 888-555-1212 पर अपडेट करें" हो सकता है।

एक साथ कतार में कई "अपडेट जो के फोन नंबर ..." कार्यों को संभव है, लेकिन विभिन्न फोन नंबरों के साथ। इस मामले में, यह सुनिश्चित करने के लिए अद्यतन लागू किए जाने चाहिए कि राज्य अंत में सही है (और नहीं, तर्क के लिए, पता पुस्तिका प्रविष्टियों पर कार्यों और टाइमस्टैम्प पर टाइमस्टैम्प डालना संभव नहीं है और दूर फेंकना संभव नहीं है बालों के काम)।

जो के लिए अद्यतन के साथ जेन आउट ऑफ़ ऑर्डर के लिए अद्यतन लागू करना सुरक्षित है।

मैं कतार की बहुसंख्यक प्रसंस्करण करना चाहता हूं, लेकिन मुझे व्यक्ति द्वारा एक्सेस सिंक्रनाइज़ करने की आवश्यकता है।

क्या इस तरह की चीज़ के लिए कोई आसान पुस्तकालय है? या क्या मैं निष्पादक का उपयोग करने और रननेबल की रन() विधि में "नाम" पर अपना स्वयं का सिंक्रनाइज़ेशन करने के लिए रुक गया हूं?

+0

मुझे लगता है कि अगर आप समझने में आसान बनाने के लिए कुछ छद्म कोड डालते हैं तो यह बेहतर होगा। लेकिन, क्या यह एक संभावना है ?: प्रति व्यक्ति एक निष्पादक की तरह कई निष्पादकों का उपयोग करने के लिए। मैंने कहा कि 'जो' –

+2

के लिए अद्यतन के साथ जेन आउट-ऑफ-ऑर्डर के लिए अद्यतन लागू करना सुरक्षित है नोट करें कि रननेबल के अंदर नाम पर सिंक्रनाइज़ करने से क्रमिक निष्पादन की गारंटी नहीं मिलेगी। एक निष्पादक यह वादा नहीं करता है कि जमा करने के क्रम में कार्य निष्पादित किए जाएंगे (जब तक कि निष्पादक एकल धागा न हो)। – Aurand

+0

@ जोस रेनाटो: मैं प्रति नाम एक थ्रेड का उपयोग करूंगा, नीचे मेरा जवाब देखें। प्रत्येक धागा आदेश स्थिरता सुनिश्चित करता है। –

उत्तर

-1

एक संभव समाधान

एक कार्य मान लें कुछ वर्ग द्वारा वर्णित है

class Task { 
    Integer taskGroup; 
    // other 
} 

जहां taskGroup एक आईडी जो अपने उदाहरण में कार्य आगमन के क्रम में प्रक्रियाओं होना है जो (पहचान करता है , प्रत्येक "नाम" अपने कार्य को परिभाषित कर सकता है समूह - या अधिक आम तौर पर - एक ही नाम wrt कार्य एक ही कार्य समूह से संबंधित हैं)।

mainTaskQueue कार्य वस्तुओं के List को इंगित करें। तब

  • एक Map<Integer,List<Task>>, कहते हैं कि taskGroupsQueues
  • के लिए प्रत्येक taskGroup एक धागा जो taskGroupsQueues.get(taskGroup) क्रमिक रूप से पर चल रही बनाने बनाएँ।
  • एक मुख्य धागे आपका मुख्य कार्य सूचियों mainTaskQueue से एक task दूर करता है और taskGroups.get(task.taskGroup)
  • एकल कतारों को मुख्य पंक्ति से कार्य स्थानांतरण और एक कतार से प्राप्त करने में कठिनाई है सिंक्रनाइज़ किए जाने के लिए यह जोड़ता है।

दूसरे शब्दों में: एक ही नाम से संबंधित कार्य एक ही थ्रेड पर निष्पादित किए जाते हैं।

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

एक और संभव समाधान(परीक्षण नहीं किया, केवल एक सुझाव)

रूप increment1s पद और Aurands टिप्पणी में बताया, taskGroup (नाम) चलने के भीतर पर तुल्यकालन कुछ समस्या है।असल में: यह बहुत देर हो चुकी है, क्योंकि निष्पादक ने दो धागे शुरू कर दिए हैं जो एक ही नाम पर सिंक करने का प्रयास करते हैं। हालांकि, आप निष्पादक स्तर पर निष्पादन के आदेश को सुनिश्चित करने का प्रयास कर सकते हैं। उदाहरण के लिए इस पोस्ट को देखें: Java Executors: how can I set task priority? (जो कि प्राथमिकताब्लॉकिंग क्यूई निष्पादक को पास करता है)।

+0

यदि मैं आपके उत्तर को सही ढंग से समझता हूं, तो इसका तात्पर्य है कि पता पुस्तिका में 1000 प्रविष्टियों के लिए, आपके पास 1000 थ्रेड हमेशा चलेंगे, और 1000 कतार (प्रत्येक थ्रेड के लिए एक) भी होगा। यह विशिष्ट प्रश्न के लिए काम कर सकता है यदि यह उपयोगकर्ताओं की एक छोटी संख्या तक सीमित है, लेकिन अन्यथा ऐसा लगता है कि इसमें स्केलेबिलिटी चिंताएं हैं। इसके अलावा, "कतार" का आपका नक्शा संभवतः वास्तविक अवरुद्ध कतारों का एक समवर्ती मानचित्र होना चाहिए और सूचियों का नक्शा नहीं होना चाहिए। –

+0

यह एक अच्छा मुद्दा है। एक साधारण संशोधन धागे की एक निश्चित संख्या का उपयोग होता है और कार्य समूह से थ्रेड आईडी में मैपिंग बनाए रखता है। हालांकि, एक अधिक इष्टतम समाधान - और यहां तक ​​कि सरल - प्राथमिकताब्लॉकिंग क्यूयू का उपयोग करना होगा। –

+2

आप यह धारणा बना रहे हैं कि कतार से ऑर्डर तत्व पुनर्प्राप्त किए गए हैं, वे क्रम में निष्पादित किए गए क्रम हैं। यह अमान्य है। – Aurand

3

एक सीधा, लेकिन बिल्कुल सही नहीं है, इस समस्या का हल एक प्रसंस्करण धागे की संख्या के बराबर एक सरणी में उप कतारों का एक सेट बनाए रखना है। एक एकल मास्टर थ्रेड आपके एकल मुख्य कतार से वस्तुओं को खींचता है और उन्हें ऑब्जेक्ट कुंजी के हैशकोड के मॉड्यूलो के माध्यम से अनुक्रमित उप कतार में जोड़ता है (जो भी आपके कार्यों को पहचानता है और उससे संबंधित है)।

उदा।

int queueIndex = myEntity.getKey().hashCode() % queues.length; 

केवल एक धागा प्रक्रियाओं है कि कतार, और एक ही इकाई के लिए सभी कार्य है कि कतार में प्रस्तुत किया जाएगा, इसलिए कोई दौड़ की स्थिति हो जाएगा।

यह समाधान अपूर्ण है क्योंकि कुछ धागे दूसरों की तुलना में बड़ी कतारों के साथ समाप्त हो सकते हैं। व्यावहारिक रूप से, यह मामला असंभव है लेकिन यह विचार करने के लिए कुछ है। सरल समाधान के साथ

मुद्दे:

एक भी कतार के बंद आइटम खींच रहा है और उसके बाद प्रभावित इकाई के लिए कुछ अलग पर ताला लगा के सरल समाधान एक रेस स्थिति है (जैसा कि Aurand ने बताया)।यह देखते हुए:

Master Queue [ Task1(entity1), Task2(entity1), ... ] 

कहाँ task1 और task2 दोनों एक ही इकाई entity1 संपादित करें, और thread1 और thread2 कतार पर काम है, तो उम्मीद/घटनाओं की वांछित अनुक्रम है है:

  • Thread1 task1 लेता है
  • ENTITY1 पर Thread1 ताले
  • Thread1 संपादित करता ENTITY1
  • गु read1 ENTITY1 बातें बताता है
  • Thread2 task2
  • Thread2 ताले ENTITY1
  • Thread2 संपादित करता है लेता है ENTITY1
  • Thread2 ENTITY1 बातें बताता है

दुर्भाग्य से, भले ही ताला थ्रेड रन विधि के पहले बयान है, यह निम्नलिखित अनुक्रम के लिए संभव है:

  • थ्रेड 1 कार्य 1
  • Thread2 task2
  • Thread2 ताले ENTITY1
  • Thread2 संपादित करता है लेता है ENTITY1
  • Thread2 ENTITY1
  • Thread1 ताले ENTITY1
  • Thread1 संपादित करता बातें बताता है ENTITY1
  • Thread1 बातें बताता है ENTITY1

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

+0

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

+0

@ क्रिस्टियनफ्रीज़ मैंने आपके जवाब को वोट नहीं दिया है, इसलिए मैं इस बात पर टिप्पणी नहीं कर सकता कि किसी भी तरह के वोटों को किस प्रकार ट्रिगर किया गया है। कतार से ऑब्जेक्ट लेने के बाद 'नाम' पर लॉक करने के बारे में मूल पोस्टर (प्रश्न पूछने वाले) टिप्पणी के संबंध में "कार्य लेना और फिर लॉक करना" के बारे में मेरी टिप्पणी है। ऐसा करने के लिए औरंड द्वारा बताई गई सूक्ष्म दौड़ की स्थिति है और मेरे जवाब में विस्तार से बताया गया है। –

+0

क्षमा करें, मुझे एहसास नहीं हुआ कि मूल प्रश्न स्पष्ट रूप से चलाने योग्य व्यक्ति के भीतर इकाई पर सिंक्रनाइज़ करने का विचार लाया। अब मैं देखता हूं कि आपने इसे क्यों लाया (अनावश्यक रूप से दोषपूर्ण) समाधान। (दुर्भाग्य से जब तक आपकी पोस्ट संपादित नहीं की जाती है, तब तक मैं अपने मतदान को वापस नहीं कर सकता, लेकिन अगर आप केवल विराम चिह्न बदलते हैं तो भी मैं ऐसा करूँगा)। W.r.t. उस सिंक्रनाइज़ेशन के लिए, मैं मुख्य थ्रेड (संबंधित कतारों पर सिंक्रनाइज़िंग) में कार्य वितरित करके अपने समाधान में इसे टालता हूं। इस प्रकार, प्रत्येक कार्यकर्ता थ्रेड केवल उस सामान को देखता है जो उसके पास है और मुख्य धागे क्रम स्थिरता सुनिश्चित करता है। –

0

इस तरह के संघर्ष हमेशा प्रत्येक ऑब्जेक्ट को एक संस्करण निर्दिष्ट करके हल किए जाते हैं। प्रत्येक अद्यतन संस्करण में वृद्धि हुई है। इसलिए यदि एक अपडेट गलत समय में आता है तो इसे खारिज कर दिया जा सकता है या देरी हो सकती है। किसी भी तरह से यह तय करने का कोई तरीका होना चाहिए कि कौन सा अपडेट पहला है और दूसरा कौन सा है। इस विधि को optimistic locking कहा जाता है।

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

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