2008-12-09 14 views
11

आपको लगता है कि थ्रेड के काम के परिणाम प्राप्त करने का सबसे अच्छा तरीका क्या है? एक थ्रेड की कल्पना करें जो कुछ गणना करता है, आप मुख्य प्रोग्राम को गणना कैसे करते हैं गणना की जाती है?थ्रेड के आउटपुट प्राप्त करना

आप "नौकरी समाप्त" या कुछ तरीके से कुछ सार्वजनिक चर के लिए प्रत्येक एक्स मिलीसेकंड को मतदान कर सकते हैं, लेकिन तब आप बाद में परिणाम प्राप्त करेंगे जब वे उपलब्ध होंगे ... मुख्य कोड समय खो जाएगा उनकी प्रतीक्षा कर रहा हूं। दूसरी तरफ, यदि आप निचले एक्स का उपयोग करते हैं, तो सीपीयू कई बार मतदान बर्बाद कर देगा।

तो, आप जानते हैं कि थ्रेड, या कुछ थ्रेड, ने अपना काम पूरा कर लिया है?

क्षमा करें अगर यह अन्य question के समान दिखता है, तो शायद यह ईबेन उत्तर का कारण है, मुझे लगता है। मेरा मतलब था कि बहुत सारे धागे चल रहे थे और जानते थे कि जब वे सभी मतदान कर चुके हैं, तो उन्हें मतदान किए बिना।

मैं थ्रेड के बैचों का उपयोग करके कई सीपीयू के बीच सीपीयू लोड साझा करने की लाइन में और सोच रहा था, और पता है कि बैच समाप्त हो गया है। मुझे लगता है कि यह भविष्य एस ऑब्जेक्ट्स के साथ किया जा सकता है, लेकिन को अवरुद्ध करना विधि एक छिपे हुए लॉक की तरह दिखता है, मुझे कुछ पसंद नहीं है।

आपके समर्थन के लिए सभी को धन्यवाद। हालांकि मैं भी एरिक्सन द्वारा जवाब पसंद आया, मुझे लगता है कि saua की सबसे पूर्ण है, और एक मैं अपने खुद के कोड में उपयोग करेंगे।

+0

> और पता है कि कब एटीएच खत्म हो गया है आप इसे क्यों जानना चाहते हैं? क्या आपको उस बैच से कुछ चाहिए? या आप जानना चाहते हैं कि आप अधिक कार्य कब कर सकते हैं? –

+0

यह इस [प्रश्न] के समान है (http://stackoverflow.com/questions/289434/how-to-make-a-java-thread-wait-for-another-threads-output)। – kgiannakakis

उत्तर

25

धागे जैसे निम्न-स्तरीय संरचनाओं का उपयोग न करें, जब तक आपको पूरी तरह से शक्ति और लचीलापन की आवश्यकता न हो।

आप ExecutorService जैसे ThreadPoolExecutor से submit()Callables का उपयोग कर सकते हैं। यह Future ऑब्जेक्ट वापस करेगा।

उस Future ऑब्जेक्ट का उपयोग करके आप आसानी से जांच सकते हैं कि यह किया गया है और परिणाम प्राप्त हो रहा है (यदि get() को अवरुद्ध कर दिया गया है तो यह अभी तक नहीं किया गया है)।

वे संरचनाएं सबसे आम थ्रेडेड ऑपरेशंस को बहुत सरल बनाती हैं।

के बारे में मैं स्पष्ट करना चाहते हैं अवरुद्ध get():

विचार यह है कि आप कुछ कार्यों (Callable रों) कि कुछ काम करना चलाना चाहते है (गणना, संसाधन का उपयोग, ...), जहाँ आप परिणाम की आवश्यकता नहीं है। जब भी चाहें अपना कोड चलाने के लिए आप केवल Executor पर निर्भर कर सकते हैं (यदि यह ThreadPoolExecutor है तो यह तब भी चलाएगा जब कोई निःशुल्क थ्रेड उपलब्ध हो)। फिर कुछ समय पर आप शायद को जारी रखने के लिए गणना के परिणाम की आवश्यकता है। इस बिंदु पर आपको get() पर कॉल करना होगा। यदि कार्य उस बिंदु पर पहले से ही चलाया गया है, तो get() तुरंत मूल्य वापस कर देगा। यदि कार्य पूरा नहीं हुआ है, तो get() कॉल कार्य पूरा होने तक प्रतीक्षा करेगा। यह आमतौर पर वांछित है क्योंकि आप कार्यों के परिणाम के बिना जारी नहीं रख सकते हैं।

आप जारी रखने के लिए मूल्य की जरूरत नहीं है जब, लेकिन इसके बारे में जानना चाहते हैं, तो यह पहले से ही उपलब्ध है (संभवतः यूआई में कुछ दिखाने के लिए) है, तो आप आसानी से isDone() कॉल कर सकते हैं और केवल get() फोन है कि अगर रिटर्न true)।

1

ए.के.ए व्यस्त प्रतीक्षा मतदान एक अच्छा विचार नहीं है। जैसा कि आपने बताया है, व्यस्त इंतजार सीपीयू चक्र को बर्बाद कर देता है और आपके आवेदन को उत्तरदायी दिखाई दे सकता है।

मेरे जावा किसी न किसी तरह है, लेकिन आप निम्नलिखित की तरह कुछ करना चाहते हैं: आप एक शर्त चर का उपयोग करना चाहिए एक धागा एक और धागे के उत्पादन के लिए इंतजार करना पड़ता है

हैं।

final Lock lock = new ReentrantLock(); 
final Condition cv = lock.newCondition(); 

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

0

जैसा कि साआ द्वारा उल्लेख किया गया है: java.util.concurrent द्वारा प्रदान की गई संरचनाओं का उपयोग करें। यदि आप प्री 1.5 (या 5.0) जेआरई के साथ फंस गए हैं, तो आप अपने आप को रोलिंग का सहारा ले सकते हैं, लेकिन आप बैकपोर्ट का उपयोग करके अभी भी बेहतर हैं: http://backport-jsr166.sourceforge.net/

1

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

इस परिदृश्य में बच्चे Thread/Runnable एक श्रोता जानता है कि कैसे परिणाम कार्रवाई करने के लिए और जो जब बच्चे Thread/Runnable पूर्ण करता वापस कहा जाता है दिया जाता है।

1

आपका परिदृश्य अभी भी थोड़ा अस्पष्ट है।

यदि आप बैच नौकरी चला रहे हैं, तो आप invokeAll का उपयोग करना चाह सकते हैं। यह आपके मुख्य धागे को तब तक अवरुद्ध कर देगा जब तक कि सभी कार्य पूर्ण नहीं हो जाते। इस दृष्टिकोण के साथ कोई "व्यस्त प्रतीक्षा" नहीं है, जहां मुख्य धागा भविष्य में isDone विधि को CPU मतदान को बर्बाद कर देगा। हालांकि यह विधि Futures की एक सूची लौटाती है, लेकिन वे पहले से ही "पूर्ण" हैं। (एक ओवरलोडेड संस्करण भी है जो पूरा होने से पहले टाइमआउट कर सकता है, जो कुछ कार्यों के साथ उपयोग करना सुरक्षित हो सकता है।) यह Future ऑब्जेक्ट्स का एक गुच्छा इकट्ठा करने की कोशिश करने से बहुत साफ हो सकता है और उनकी स्थिति या उनके ब्लॉक को जांचने की कोशिश कर रहा है get व्यक्तिगत रूप से विधियों।

यदि यह एक इंटरैक्टिव एप्लिकेशन है, तो callback का उपयोग करके कार्यों को स्पोरैडिक रूप से क्रियान्वित करने के लिए, nick.holt द्वारा सुझाए गए एक महान दृष्टिकोण है। यहां, आप submitRunnable का उपयोग करते हैं। run विधि गणना के दौरान परिणाम के साथ कॉलबैक को आमंत्रित करती है। इस दृष्टिकोण के साथ, आप Future को submit द्वारा लौटा सकते हैं, जब तक कि आप पूरे ExecutorService को बंद किए बिना cancel चल रहे कार्यों को सक्षम नहीं करना चाहते हैं।

यदि आप कार्यों को रद्द करने या टाइमआउट क्षमताओं का उपयोग करने में सक्षम होना चाहते हैं, तो याद रखने की एक महत्वपूर्ण बात यह है कि interrupt को उनके धागे पर कॉल करके कार्य रद्द कर दिया जाता है। इसलिए, आपके कार्य को समय-समय पर interrupted status जांचना होगा और आवश्यकतानुसार निरस्त करना होगा।

1

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

इसका उपयोग केवल तभी करें जब आपको असीमित गतिविधि को बंद करने की आवश्यकता हो, आप प्रतीक्षा करते समय कुछ काम करें, और फिर परिणाम प्राप्त करें। अन्यथा, थ्रेड का बिंदु क्या है? आप एक वर्ग भी लिख सकते हैं जो काम करता है और परिणाम को मुख्य धागे में देता है।

एक और दृष्टिकोण कॉलबैक होगा: क्या आपका कन्स्ट्रक्टर एक तर्क लेता है जो एक कॉलबैक विधि के साथ एक इंटरफ़ेस लागू करता है जिसे परिणाम गणना के समय बुलाया जाएगा। यह काम पूरी तरह से असीमित बना देगा। लेकिन अगर आपको किसी बिंदु पर परिणाम की प्रतीक्षा करने की ज़रूरत है, तो मुझे लगता है कि आपको अभी भी मुख्य धागे से शामिल() को कॉल करने की आवश्यकता होगी।

4

आप एक लिस्टर इंटरफ़ेस बना सकते हैं कि मुख्य कार्यक्रम लागू करता है जिसे कार्यकर्ता द्वारा उसके काम को निष्पादित करने के बाद बुलाया जाता है।

इस तरह आपको मतदान करने की आवश्यकता नहीं है।

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

/** 
* Thread to perform work 
*/ 
public class WorkerThread implements Runnable { 
    private List listeners = new ArrayList(); 
    private List results; 

    public void run() { 
     // Do some long running work here 

     try { 
      // Sleep to simulate long running task 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     results = new ArrayList(); 
     results.add("Result 1"); 

     // Work done, notify listeners 
     notifyListeners(); 
    } 

    private void notifyListeners() { 
     for (Iterator iter = listeners.iterator(); iter.hasNext();) { 
      WorkerListener listener = (WorkerListener) iter.next(); 
      listener.workDone(this); 
     } 
    } 

    public void registerWorkerListener(WorkerListener listener) { 
     listeners.add(listener); 
    } 

    public List getResults() { 
     return results; 
    } 
} 

और अंत में, मुख्य कार्यक्रम शुरू होता है:

/** 
* Listener interface to implement to be called when work has 
* finished. 
*/ 
public interface WorkerListener { 
    public void workDone(WorkerThread thread); 
} 

यहाँ वास्तविक धागा जो कुछ काम करता है और यह श्रोताओं है सूचित करता है की एक उदाहरण है:

यहाँ एक उदाहरण स्वरूप है एक कार्यकर्ता थ्रेड और काम करने के बाद अधिसूचित होने के लिए एक श्रोता को पंजीकृत किया जाता है:

import java.util.Iterator; 
import java.util.List; 

/** 
* Class to simulate a main program 
*/ 
public class MainProg { 
    public MainProg() { 
     WorkerThread worker = new WorkerThread(); 
     // Register anonymous listener class 
     worker.registerWorkerListener(new WorkerListener() { 
      public void workDone(WorkerThread thread) { 
       System.out.println("Work done"); 
       List results = thread.getResults(); 
       for (Iterator iter = results.iterator(); iter.hasNext();) { 
        String result = (String) iter.next(); 
        System.out.println(result); 
       } 
      } 
     }); 

     // Start the worker thread 
     Thread thread = new Thread(worker); 
     thread.start(); 

     System.out.println("Main program started"); 
    } 

    public static void main(String[] args) { 
     MainProg prog = new MainProg(); 
    } 
} 
संबंधित मुद्दे