2012-04-04 26 views
5

मेरी एक ऐसी स्थिति है जहां विभिन्न धागे एक कतार (उत्पादक) को पॉप्युलेट करते हैं और एक उपभोक्ता इस कतार से तत्व पुनर्प्राप्त करता है। मेरी समस्या यह है कि जब इन तत्वों में से एक को कतार से पुनर्प्राप्त किया जाता है तो कुछ याद किया जाता है (गायब सिग्नल?)। उत्पादकों कोड है:जावा समेकन: बहु-निर्माता एक उपभोक्ता

class Producer implements Runnable { 

    private Consumer consumer; 

    Producer(Consumer consumer) { this.consumer = consumer; } 

    @Override 
public void run() { 
    consumer.send("message"); 
    } 
} 

और वे बनाया है और साथ चलाए जा रहे हैं:

ExecutorService executor = Executors.newSingleThreadExecutor(); 
for (int i = 0; i < 20; i++) { 
    executor.execute(new Producer(consumer)); 
} 

उपभोक्ता कोड है:

class Consumer implements Runnable { 

private Queue<String> queue = new ConcurrentLinkedQueue<String>(); 

void send(String message) { 
    synchronized (queue) { 
     queue.add(message); 
     System.out.println("SIZE: " + queue.size()); 
     queue.notify(); 
    } 
} 

@Override 
public void run() { 
    int counter = 0; 
    synchronized (queue) { 
    while(true) { 
     try { 
      System.out.println("SLEEP"); 
       queue.wait(10); 
     } catch (InterruptedException e) { 
       Thread.interrupted(); 
     } 
     System.out.println(counter); 
     if (!queue.isEmpty()) {    
      queue.poll(); 
      counter++; 
     } 
    } 
    } 
} 

} 

जब कोड चलता है मैं कभी कभी 20 तत्वों को जोड़ा हो और 20 पुनर्प्राप्त, लेकिन अन्य मामलों में पुनर्प्राप्त तत्व 20 से कम हैं। किसी भी विचार को ठीक करने के लिए कैसे?

+0

आप निम्न-स्तरीय सिंक्रनाइज़ेशन संरचनाओं ('प्रतीक्षा', 'सूचित करें') और उच्च-स्तरीय वाले (' ConcurrentLinkedQueue', 'execorService') के अजीब मिश्रण का उपयोग कर रहे हैं। एक या दूसरे का प्रयोग करें! – artbristol

+0

मैंने यह किया लेकिन दोनों मामलों में मुझे एक ही समस्या है – Randomize

+0

मैं वास्तव में उपभोक्ता चलाता कोड नहीं देख सकता। – dhblah

उत्तर

10

मुझे सुझाव है कि आप एक कतार के बजाय ब्लॉकिंगक्यूयू का उपयोग करें। एक LinkedBlockingDeque आपके लिए एक अच्छा उम्मीदवार हो सकता है।

आपका कोड इस तरह दिखेगा:

void send(String message) { 
    synchronized (queue) { 
     queue.put(message); 
     System.out.println("SIZE: " + queue.size()); 
    } 
} 

और फिर आप के लिए सिर्फ

queue.take() 
अपने उपभोक्ता धागा

पर

आवश्यकता होगी विचार है कि .take है() होगा जब तक कोई कतार में कोई आइटम उपलब्ध न हो तब तक ब्लॉक करें और फिर एक (जहां मुझे लगता है कि आपका कार्यान्वयन पीड़ित है: अनुपलब्ध अधिसूचना whil ई मतदान)। .put() आपके लिए सभी अधिसूचनाएं करने के लिए ज़िम्मेदार है। कोई प्रतीक्षा/जरूरी नहीं है।

+0

लिंक किए गए ब्लॉक्लिंग डिक की कोशिश की लेकिन मुझे अभी भी एक ही समस्या मिली है – Randomize

+0

@Randomize क्या आप ब्लॉकिंगक्यूयू का उपयोग करने वाले समस्याग्रस्त कोड का एक उदाहरण पोस्ट कर सकते हैं? उपभोक्ता कोड पर्याप्त होना चाहिए। – charisis

+0

मैं ऊपर एक ही कोड का पुन: उपयोग कर रहा हूं मैंने लिंकडब्लॉकिंगडेक के साथ ConcurrentLinkedQueue को अभी बदल दिया है। – Randomize

2

आपके कोड में समस्या शायद इसलिए है क्योंकि आप notifyAll के बजाय notify का उपयोग कर रहे हैं। यदि लॉक पर कोई इंतजार कर रहा है तो पूर्व केवल एक धागा जगाएगा। यह दौड़ की स्थिति की अनुमति देता है जहां कोई धागा इंतजार नहीं कर रहा है और सिग्नल गुम हो गया है। एक अधिसूचना सभी नाबालिग प्रदर्शन लागत पर शुद्धता को मजबूर कर देगा ताकि सभी थ्रेडों को यह जांचने के लिए जागृत किया जा सके कि वे लॉक प्राप्त कर सकते हैं या नहीं।

यह Effective Java 1st ed में सबसे अच्छा समझाया गया है (पी .150 देखें)। दूसरे संस्करण ने इस टिप को हटा दिया क्योंकि प्रोग्रामर से java.util.concurrent का उपयोग करने की उम्मीद है जो मजबूत शुद्धता गारंटी प्रदान करता है।

+0

मैंने अधिसूचित किया लेकिन सभी काम नहीं किया – Randomize

+0

एक उपभोक्ता है इसलिए सूचित/सूचित करें सभी कोई फर्क नहीं पड़ता –

1

यह एक ही समय में ConcurrentLinkedQueue और सिंक्रनाइज़ेशन दोनों का उपयोग करने के लिए बुरा विचार दिखता है। यह समवर्ती डेटा संरचनाओं के उद्देश्य को पहली जगह में खारिज कर देता है।

ConcurrentLinkedQueue डेटा संरचना के साथ कोई समस्या नहीं है और इसे ब्लॉकिंगक्यूयू के साथ बदलकर समस्या हल हो जाएगी लेकिन यह मूल कारण नहीं है।

समस्या queue.wait (10) के साथ है। यह समय प्रतीक्षा विधि है। 10ms elapses के बाद यह फिर से लॉक प्राप्त होगा।

  1. सूचना (queue.notify()) क्योंकि ऐसा कोई उपभोक्ता धागा अगर 10ms बीत जाने पर उस पर इंतज़ार कर रहा है खो दिया हो जाएगा।

  2. निर्माता कतार में जोड़ने में सक्षम नहीं होंगे क्योंकि वे लॉक प्राप्त नहीं कर सकते हैं क्योंकि उपभोक्ता द्वारा लॉक का दावा किया जाता है।

BlockingQueue में जाने से आपका समस्या है क्योंकि आप अपने प्रतीक्षा (10) कोड हटा दिया और प्रतीक्षा करें और सूचित BlockingQueue डेटा संरचना से ख्याल रखा गया था हल किया।

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