2009-02-06 16 views
5

के बीच एक कार्य आइटम पास करना मेरे पास दो धागे हैं। निर्माता डेटा के टुकड़े (स्ट्रिंग ऑब्जेक्ट्स) का उत्पादन कर रहा है, जहां उपभोक्ता इन तारों को संसाधित करता है। पकड़ यह है कि मेरे आवेदन को संसाधित होने के लिए केवल हालिया डेटा ऑब्जेक्ट की आवश्यकता है। दूसरे शब्दों में, यदि निर्माता दो स्ट्रिंग्स "एस 1" और फिर "एस 2" का उत्पादन करने में कामयाब रहा तो मैं चाहता हूं कि उपभोक्ता केवल "एस 2" को संसाधित करे। "एस 1" सुरक्षित रूप से त्याग दिया जा सकता है।धागे (जावा)

बेशक इस वर्ग को समझने वाली कक्षा को लागू करने में कोई समस्या नहीं है, लेकिन मैं java.util.concurrent (यदि ऐसा तंत्र मौजूद है) से मानक तंत्र का उपयोग करना चाहता हूं। ध्यान दें कि सिंक्रोनस क्यूई एक अच्छा समाधान नहीं है: उपभोक्ता "एस 1" को घेरते समय ब्लॉक करेगा और "एस 2" उत्पादन करने का मौका नहीं मिलेगा।

कोई भी विचार (संक्षेप में, मैं एक एकल तत्व संग्रह के लिए एक अवरुद्ध आपरेशन को हटाने और एक गैर अवरुद्ध सेट संचालन के साथ देख रहा हूँ)?

उत्तर

3

मुझे लगता है कि अपने सबसे अच्छे जवाब शायद ArrayBlockingQueue, जहां निर्माता (आप केवल है उपयोग करने के लिए है एक निर्माता, सही?) नया तत्व जोड़ने से पहले किसी भी मौजूदा तत्व को हटा देता है।

निश्चित रूप से, इस कार्यान्वयन में दौड़ की स्थिति है: उपभोक्ता इसे हटाए जाने से ठीक पहले तत्व को संसाधित करना शुरू कर सकता है। लेकिन उन दौड़ की स्थिति हमेशा मौजूद रहेगी, इससे कोई फर्क नहीं पड़ता कि आप किस डेटा संरचना का उपयोग करते हैं।

+0

क्या वास्तव में दौड़ की स्थिति है? मुझे लगता है कि ArrayBlockingQueue के अंदर ReentrantLock उनसे बचने के लिए है। –

+0

@Errandir - जिस दौड़ की स्थिति का मैं जिक्र कर रहा था वह था जब कतार पर प्रतीक्षा करने वाला कोई तत्व रहा था, और उपभोक्ता उस तत्व को लेता है जब निर्माता एक नया तत्व जोड़ता है। यह एक बेहतर अवधि की कमी के लिए है, एक "मैक्रो रेस" जो आपके द्वारा उपयोग की जाने वाली किसी भी डेटा संरचना के बाहर होती है। – kdgregory

0

आप उस के लिए आकार एक की एक सरणी इस्तेमाल कर सकते हैं:

String[] oeq = new String[1]; 

नमूना स्रोत:

public class Test { 
    private static final String[] oeq = new String[1]; 
    public static void main(String[] args) { 
     (new Producer()).start(); 
     (new Consumer()).start(); 
     (new Consumer()).start(); 
     (new Consumer()).start(); 
     (new Consumer()).start(); 
     (new Consumer()).start(); 
     (new Consumer()).start(); 
    } 

    private static class Producer extends Thread { 
     public void run() { 
      int i=0; 
      while(true) { 
       i++; 
       synchronized(oeq) { 
        oeq[0] = ""+i; 
        oeq.notifyAll(); 
       } 
      } 
     } 
    } 

    private static class Consumer extends Thread { 
     public void run() { 
      String workload = null; 
      while(true) { 
       synchronized(oeq) { 
        try { 
         oeq.wait(); 
        } catch(InterruptedException ie) { 
         ie.printStackTrace(); 
        } 
        if(oeq[0] != null) { 
         workload = oeq[0]; 
         oeq[0] = null; 
        } 
       } 
       if(workload != null) { 
        System.out.println(workload); 
       } 
      } 
     } 
    } 
} 
+0

यह बहुत अक्षम होगा। उपभोक्ता धागे को काम की प्रतीक्षा करते समय सीपीयू को अवरुद्ध नहीं करना चाहिए। –

+0

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

+0

दोनों संकेत सत्य हैं, मैंने पहले को तय किया, धन्यवाद। –

3

Exchanger कक्षा के बारे में क्या? धागे के बीच वस्तुओं का आदान-प्रदान करने का यह मानक तरीका है। इसे अपनी कक्षा के साथ विशेषज्ञ बनाएं, तारों की एक सूची हो सकती है। उपभोक्ता को केवल पहले/आखिरी का उपयोग करें।

+0

शायद मेरे से बेहतर दृष्टिकोण है, हालांकि आपको उत्पादक का टाइमआउट 0 – kdgregory

+0

पर सेट करने की आवश्यकता है, एक्सचेंजर निर्माता को अवरुद्ध करता है :-( –

+0

जब तक कि आप टाइमआउट को 0 (या ऋणात्मक संख्या) – kdgregory

0

ठीक है, अगर आप केवल हाल ही में उत्पादित स्ट्रिंग चाहते हैं, तो आपको कतार की आवश्यकता नहीं है - आपको केवल एक स्ट्रिंग संदर्भ चाहिए: निर्माता इसे सेट करता है, उपभोक्ता इसे पढ़ता है। यदि उपभोक्ता इसे पढ़ने के लिए इतना लंबा समय लेता है कि निर्माता इसे फिर से सेट करता है ... तो क्या?

संदर्भों को सेट करना और पढ़ना परमाणु हैं। एकमात्र मुद्दा यह है कि यदि आप उपभोक्ता को किसी भी तरह सूचित करना चाहते हैं कि एक स्ट्रिंग उपलब्ध है। लेकिन तब भी ... यदि उपभोक्ता कुछ ऐसा कर रहा है जो थोड़ी देर लेता है, तो आपको वास्तव में समवर्ती पुस्तकालयों से किसी भी फैंसी-पैंट सामान की आवश्यकता नहीं होती है।

नोट, बीटीडब्ल्यू, यह उदाहरण किसी भी निर्माता और/या उपभोक्ता धागे के साथ काम करता है।

import java.util.Random; 

public class Example { 
    public static void main(String[] av) { 
     new Example().go(); 
    } 

    Object mutex  = new Object(); 
    String theString = null; 

    void go() { 
     Runnable producer = new Runnable() { 
      public void run() { 
       Random rnd = new Random(); 
       try { 
        for (;;) { 
         Thread.sleep(rnd.nextInt(10000)); 
         synchronized (mutex) { 
          theString = "" + System.currentTimeMillis(); 
          System.out.println("Producer: Setting string to " + theString); 
          mutex.notify(); 
         } 
        } 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

      } 
     }; 

     Runnable consumer = new Runnable() { 
      public void run() { 
       try { 
        String mostRecentValue = null; 
        Random rnd = new Random(); 
        for (;;) { 
         synchronized (mutex) { 
          // we use == because the producer 
          // creates new string 
          // instances 
          if (theString == mostRecentValue) { 
           System.out.println("Consumer: Waiting for new value"); 
           mutex.wait(); 
           System.out.println("Consumer: Producer woke me up!"); 
          } else { 
           System.out.println("Consumer: There's a new value waiting for me"); 
          } 
          mostRecentValue = theString; 
         } 
         System.out.println("Consumer: processing " + mostRecentValue); 
         Thread.sleep(rnd.nextInt(10000)); 
        } 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     }; 


     new Thread(producer).start(); 
     new Thread(consumer).start(); 
    } 
} 
+0

पर सेट न करें, आपको संदर्भ को अस्थिर बनाना होगा, और 1.5+ जेडीके में चलने के लिए, इसकी गारंटी के लिए (जावा मेमोरी मॉडल थ्रेड को अपनी प्रतिलिपि अनिश्चित काल तक बनाए रखने की इजाजत देता है) – kdgregory

+0

यूप - उस बिट को भूल गया। – paulmurray

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