क्या एक ही थ्रेड पर दो बार प्रारंभ विधि को कॉल करना कानूनी है?


90

निम्न कोड java.lang.IllegalThreadStateException: Thread already startedतब होता है जब मैंने प्रोग्राम में दूसरी बारstart() विधि को बुलाया ।

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

ऐसा दूसरी बार updateUI.start()कहा जाता है। मैंने कई बार इसके माध्यम से कदम रखा है और धागा कहा जाता है और मारने से पहले पूरा करने के लिए चलाता है updateUI.start()

कॉल करने updateUI.run()से त्रुटि से बचा जाता है, लेकिन थ्रेड UI थ्रेड (कॉलिंग थ्रेड, जैसा कि SO पर अन्य पोस्ट्स में उल्लिखित है) में चलने का कारण बनता है, जो कि मैं नहीं चाहता।

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


9
आपने सिर्फ थ जेवाडॉक क्यों नहीं पढ़ा - यह स्पष्ट रूप से वें अनुबंध का वर्णन करता है।
एम.पी.

जवाबों:


112

से जावा API विनिर्देश के लिए Thread.startविधि:

एक से अधिक बार एक धागा शुरू करना कभी भी कानूनी नहीं है। विशेष रूप से, एक थ्रेड को फिर से शुरू नहीं किया जा सकता है क्योंकि यह निष्पादन पूरा कर चुका है।

इसके अलावा:

फेंकता है:
IllegalThreadStateException- यदि धागा पहले से ही शुरू किया गया था।

तो हाँ, एक Threadबार ही शुरू किया जा सकता है।

यदि ऐसा है तो मुझे क्या करना चाहिए अगर मैं फिर से धागा चलाना चाहता हूं?

यदि एक Threadसे अधिक बार चलाने की आवश्यकता है, तो किसी को इसका एक नया उदाहरण बनाना चाहिए Threadऔर startउस पर कॉल करना चाहिए।


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

@ कोड, यदि मैं पुराने थ्रेड ऑब्जेक्ट नाम को एक नए थ्रेड () के लिए असाइन करता हूं, तो पुराने थ्रेड के समाप्त होने के बाद, क्या पुराने थ्रेड को कचरा एकत्र किया जाएगा (यानी यह स्वचालित रूप से पुनर्नवीनीकरण है, या इसे स्पष्ट रूप से किया जाना चाहिए)?
Snapfractalpop

यह कचरा एकत्र किया जाएगा, जब तक कि थ्रेड नहीं चल रहा है।
उड़ता हुआ

1
यह उत्तर थोड़ा पुराना है। यदि एक आधुनिक जावा प्रोग्राम को एक से अधिक बार कार्य करने की आवश्यकता है , तो उसे Threadहर बार एक नया नहीं बनाना चाहिए । इसके बजाय, उसे कार्य को थ्रेड पूल (जैसे java.util.concurrent.ThreadPoolExecutor) में प्रस्तुत करना चाहिए
सोलोमन स्लो

13

बिल्कुल सही। प्रलेखन से :

एक से अधिक बार एक धागा शुरू करना कभी भी कानूनी नहीं है। विशेष रूप से, एक थ्रेड को फिर से शुरू नहीं किया जा सकता है क्योंकि यह निष्पादन पूरा कर चुका है।

बार-बार गणना के लिए आप क्या कर सकते हैं, इसके संदर्भ में, ऐसा लगता है जैसे आप SwingUtilities InvokeLater विधि का उपयोग कर सकते हैं । आप पहले से ही run()सीधे कॉलिंग के साथ प्रयोग कर रहे हैं, जिसका अर्थ है कि आप पहले से ही Runnableकच्चे के बजाय उपयोग करने के बारे में सोच रहे हैं ThreadinvokeLaterकेवल Runnableकार्य पर विधि का उपयोग करने का प्रयास करें और देखें कि क्या यह आपके मानसिक पैटर्न को थोड़ा बेहतर बनाता है।

यहाँ प्रलेखन से उदाहरण है:

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

यदि आप उस printlnकॉल को अपनी गणना के साथ बदलते हैं , तो यह ठीक वैसा ही हो सकता है जैसा आपको चाहिए।

संपादित करें: टिप्पणी के बाद, मैंने मूल पोस्ट में Android टैग नहीं देखा था। Android कार्य में InvokeLater के बराबर है Handler.post(Runnable)। इसके जावदोक से:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

तो, एंड्रॉइड दुनिया में, आप ऊपर दिए गए एक ही उदाहरण का उपयोग कर सकते हैं, Swingutilities.invokeLaterउपयुक्त पोस्ट के साथ बदलकर ए Handler


ओपी एंड्रॉइड पर थ्रेडिंग के बारे में पूछ रहा है, जिसमें स्विंगिंग यूटिलिटीज शामिल नहीं हैं।
ऑस्टिन महोनी

@ ऑस्टिन, आप सही कह रहे हैं। मैंने समानांतर Android कोड को चित्रित करने के लिए हैंडलर.पोस्ट () के बारे में टिप्पणी को जोड़ा।
बॉब क्रॉस

1
एक और तरीका है अगर आप अपने यूआई को अपडेट करने की कोशिश कर रहे हैं RunOnUIThread(Runnable)या View.post(Runnable)अपने खुद के हैंडलर बनाने के बजाय। ये मुख्य थ्रेड पर रन करने योग्य चलाएंगे जिससे आप UI को अपडेट कर सकेंगे।
ऑस्टिन महोनी

3

अभी-अभी आया उत्तर कवर करता है कि आपको वह क्यों नहीं करना चाहिए जो आप कर रहे हैं। आपकी वास्तविक समस्या को हल करने के लिए यहां कुछ विकल्प दिए गए हैं।

यह विशेष रूप से थ्रेड पृष्ठभूमि में कुछ गणना कर रहा है, अगर मैं इसे थ्रेड में नहीं करता हूं तो यह यूआई थ्रेड में किया जाता है और उपयोगकर्ता को अनुचित रूप से लंबा इंतजार है।

अपने खुद के धागे और उपयोग डंप AsyncTask

या जब ज़रूरत हो एक नया धागा बनाएँ।

या धागे को LinkedBlockingQueueफिर से शुरू करने के बजाय एक काम कतार (जैसे ) से संचालित करने के लिए अपना धागा सेट करें ।


3

नहीं , हम थ्रेड को फिर से शुरू नहीं कर सकते हैं, ऐसा करने से रनटाइम एक्ससेप्शन java.lang.IllegalThreadStateException फेंक देगा। >

एक बार चलाने के कारण () विधि थ्रेड द्वारा निष्पादित की जाती है, यह मृत अवस्था में चली जाती है।

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

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * OUTPUT रन में () विधि, विधि पूर्ण। थ्रेड में मुख्य "java.lang.IllegalThreadStateException पर java.lang.Thread.start (अज्ञात स्रोत) * /

इसे देखो


2

आपको क्या करना चाहिए एक रननेबल बनाने के लिए और हर बार जब आप रननेबल को चलाना चाहते हैं, तो एक नए थ्रेड के साथ लपेटें। यह वास्तव में करने के लिए बदसूरत होगा, लेकिन आप फिर से इसके लिए कोड को चलाने के लिए एक धागे के साथ एक धागा लपेट सकते हैं लेकिन केवल यह है कि क्या आपको वास्तव में करना है।


किसी भी स्निपेट, कैसे लपेटें?
विनय

1

जैसा कि आपने कहा, एक धागा एक से अधिक बार शुरू नहीं किया जा सकता है।

सीधे घोड़े के मुंह से: जावा एपीआई युक्ति

एक से अधिक बार एक धागा शुरू करना कभी भी कानूनी नहीं है। विशेष रूप से, एक थ्रेड को फिर से शुरू नहीं किया जा सकता है क्योंकि यह निष्पादन पूरा कर चुका है।

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


0

जावा एपीआई में एक धागे को फिर से उपयोग करने के लिए अवैध कार्रवाई है। हालाँकि, आप इसे एक लागू करने योग्य कार्यान्वयन में लपेट सकते हैं और उस उदाहरण को फिर से चला सकते हैं।


0

हाँ, हम पहले से ही चल रहे धागे को शुरू नहीं कर सकते। यह IllegalThreadStateException को रनटाइम पर फेंक देगा - यदि धागा पहले ही शुरू हो गया था।

क्या होगा यदि आपको वास्तव में थ्रेड शुरू करने की आवश्यकता है: विकल्प 1) यदि किसी थ्रेड को एक से अधिक बार चलाने की आवश्यकता है, तो किसी को थ्रेड का एक नया उदाहरण बनाना चाहिए और उस पर कॉल शुरू करना चाहिए।


0

क्या केवल एक बार थ्रेड शुरू किया जा सकता है?

हाँ। आप इसे एक बार शुरू कर सकते हैं।

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

Threadफिर से मत भागो । इसके बजाय बनाने Runnable और पर पोस्ट हैंडलर की HandlerThread । आप कई Runnableऑब्जेक्ट सबमिट कर सकते हैं। यदि आप अपने Runnable run()तरीके से UI थ्रेड में डेटा भेजना चाहते हैं , तो UI थ्रेड और प्रक्रिया Messageपर पोस्ट करेंHandlerhandleMessage

उदाहरण कोड के लिए इस पोस्ट का संदर्भ लें:

Android: एक धागे में टोस्ट


0

मुझे नहीं पता कि यह अच्छा अभ्यास है, लेकिन जब मैंने रन () रन के अंदर कहा जाता है () विधि तो यह कोई त्रुटि नहीं फेंकता है और वास्तव में वही करता है जो मैं चाहता था।

मुझे पता है कि यह फिर से एक धागा शुरू नहीं कर रहा है, लेकिन शायद यह आपके लिए काम आता है।

public void run() {

    LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();

    try {
        NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
        Thread.sleep(5000);
        if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
            System.out.println("{There was a NetworkState change!}");
            run();
        } else {
            run();
        }
    } catch (SocketException | InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
    checkingNetworkStates.start();
}

आशा है कि यह मदद करता है, भले ही यह थोड़ा ही हो।

चियर्स


-1

यह वास्तव में करने के लिए बदसूरत होगा, लेकिन आप फिर से इसके लिए कोड को चलाने के लिए एक धागे के साथ एक धागा लपेट सकते हैं लेकिन केवल यह है कि क्या आपको वास्तव में करना है।

मुझे एक संसाधन रिसाव को ठीक करना पड़ा है जो एक प्रोग्रामर के कारण था जिसने थ्रेड बनाया था, लेकिन इसके बजाय स्टार्ट () आईएनजी, उसने रन () - विधि को सीधे कहा। इसलिए इससे बचें, जब तक आप वास्तव में नहीं जानते कि इसके क्या दुष्प्रभाव होते हैं।


लेकिन यह सुझाव run()सीधे तौर पर कॉल करने के लिए नहीं था , बस एक थ्रेडेबल को थ्रेड में एम्बेड करने के लिए और संभवतः इनवोक करने के लिए start()
H2ONaCl

@ H2ONaCl यदि आप मेरे द्वारा उद्धृत पाठ को पढ़ते हैं, तो सुझाव एक थ्रेड को थ्रेड में लपेटने का था। यह हो सकता है कि संपादित करने से पहले आपको मूल सुझाव पढ़ने को न मिले।
तोरबन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.