Java में "Runnable" बनाम "थ्रेड का विस्तार" लागू होता है


2118

मैंने जावा में थ्रेड्स के साथ कितने समय बिताए हैं, मैंने थ्रेड लिखने के इन दो तरीकों को पाया है:

के साथ implements Runnable:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

या, के साथ extends Thread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

क्या कोड के इन दो ब्लॉकों में कोई महत्वपूर्ण अंतर है?


57
इस सवाल के लिए धन्यवाद, जवाब ने मुझे बहुत सारी गलतफहमियों को दूर किया। मैंने एसओ के अस्तित्व में आने से पहले जावा थ्रेड्स को करने के सही तरीके पर ध्यान दिया और वहां से बहुत सारी गलत जानकारी / पुरानी जानकारी मिली।
जेम्स मैकमोहन

5
एक कारण हो सकता है कि आप थ्रेड का विस्तार करना चाहें ( लेकिन मैं इसकी अनुशंसा नहीं करता ), आप प्राथमिक रूप से संभाल सकते हैं interrupt()। फिर से, यह एक विचार है, यह सही मामले में उपयोगी हो सकता है, हालांकि मैं इसकी सिफारिश नहीं करता हूं।
bestsss

कृपया उत्तर भी देखें, अच्छी तरह से समझाया गया: stackoverflow.com/q/5562720/285594

@bestsss, मैं यह पता लगाने की कोशिश कर रहा हूं कि व्यवधान से निपटने के बारे में आपका क्या मतलब हो सकता है ()। क्या आप विधि को ओवरराइड करने की कोशिश कर रहे हैं?
बॉब क्रॉस

8
हां। कोड के अनुसार, क्लास थ्रेड ए किसी भी वर्ग का विस्तार कर सकता है, जबकि क्लास थ्रेड बी किसी अन्य वर्ग का विस्तार नहीं कर सकता है
मणि डीपैक

जवाबों:


1672

हां: इसे लागू करने Runnableका सबसे पसंदीदा तरीका IMO है। आप वास्तव में थ्रेड के व्यवहार के विशेषज्ञ नहीं हैं। आप इसे चलाने के लिए कुछ दे रहे हैं। इसका मतलब है कि रचना जाने के लिए दार्शनिक रूप से "शुद्ध" है।

में व्यावहारिक दृष्टि से, यह आप लागू कर सकते हैं इसका मतलब है Runnableऔर एक अन्य वर्ग के साथ-साथ विस्तार।


151
ठीक है, अच्छी तरह से डाल दिया। थ्रेड को अधिलेखित करने के लिए हम किस व्यवहार की कोशिश कर रहे हैं? मेरा तर्क है कि अधिकांश लोग किसी भी व्यवहार को अधिलेखित करने की कोशिश नहीं कर रहे हैं, लेकिन थ्रेड के व्यवहार का उपयोग करने की कोशिश कर रहे हैं।
5:50 बजे

87
एक साइड कमेंट के रूप में, यदि आप थ्रेड को इंस्टाल करते हैं और इसकी शुरुआत () विधि को नहीं कहते हैं, तो आप जावा <5 में मेमोरी लीक बना रहे हैं (यह रनवेबल्स के साथ नहीं होता है): stackoverflow.com/questions/107823/…
Nachor Coloma

25
रननेबल का एक मामूली फायदा यह है कि, अगर कुछ परिस्थितियों में आप परवाह नहीं करते हैं, या थ्रेडिंग का उपयोग नहीं करना चाहते हैं, और आप कोड को निष्पादित करना चाहते हैं, तो आपके पास रन रन () कॉल करने का विकल्प है। उदाहरण के लिए (बहुत हॅंडवी) if (numberCores > 4) myExecutor.excute(myRunnable); else myRunnable.run()
user949300

10
@ user949300 आप यह भी कर सकते हैं कि extends Threadअगर आप ऐसा नहीं करना चाहते हैं तो आप क्यों लागू करना चाहेंगे Runnable...
m0skit0

30
सिएरा और बेट्स को पैराफ्रेज करने के लिए, रननेबल को लागू करने का एक प्रमुख लाभ यह है कि आप "धावक" से "नौकरी" को वास्तुशिल्प रूप से अलग कर रहे हैं।
8bitjunkie

569

tl; dr: implements Runnable बेहतर है। हालांकि, चेतावनी महत्वपूर्ण है

सामान्य तौर पर, मैं इसके Runnableबजाय कुछ का उपयोग करने की सलाह दूंगा Threadक्योंकि यह आपको अपने काम को केवल संक्षिप्त रूप से अपनी पसंद के साथ युग्मित रखने की अनुमति देता है। उदाहरण के लिए, यदि आप एक का उपयोग करते हैं Runnableऔर बाद में तय करते हैं कि यह वास्तव में इसकी आवश्यकता नहीं है Thread, तो आप बस थ्रेड.ए.आर. () कह सकते हैं।

कैविएट: यहां के आसपास, मैं कच्चे धागे के उपयोग को दृढ़ता से हतोत्साहित करता हूं। मैं Callables और FutureTasks (javadoc से: "एक रद्द करने योग्य अतुल्यकालिक गणना") का उपयोग करना पसंद करता हूं । टाइमआउट्स का एकीकरण, उचित रद्द करना और आधुनिक संगामिति समर्थन के थ्रेड पूलिंग कच्चे धागे के ढेर की तुलना में मेरे लिए बहुत अधिक उपयोगी हैं।

फॉलो-अप: एक FutureTaskकंस्ट्रक्टर है जो आपको रननेबल्स का उपयोग करने की अनुमति देता है (यदि ऐसा है जो आप सबसे अधिक आरामदायक हैं) और फिर भी आधुनिक कंसीडर टूल्स का लाभ प्राप्त करें। जावदोक को उद्धृत करने के लिए :

यदि आपको किसी विशेष परिणाम की आवश्यकता नहीं है, तो फ़ॉर्म के निर्माण का उपयोग करने पर विचार करें:

Future<?> f = new FutureTask<Object>(runnable, null)

इसलिए, यदि हम उन्हें अपने runnableसाथ प्रतिस्थापित करते हैं, तो हमें threadAनिम्नलिखित मिलते हैं:

new FutureTask<Object>(threadA, null)

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

यदि आप एक थ्रेड पूल का उपयोग करने का प्रयास करना चाहते हैं, तो ऊपर दिए गए कोड का टुकड़ा निम्नलिखित की तरह कुछ हो जाएगा ( Executors.newCachedThreadPool () फ़ैक्टरी विधि का उपयोग करके ):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

40
यह स्वीकृत उत्तर IMHO से बेहतर है। एक बात: आपके पास कोड का स्निपेट निष्पादक को बंद नहीं करता है और मैं लाखों सवाल देखता हूं, जहां लोगों को यह गलत लगता है, हर बार जब वे एक कार्य को शुरू करना चाहते हैं, तो एक नया निष्पादनकर्ता बनाते हैं। esएक स्थिर (या इंजेक्शन) क्षेत्र के रूप में बेहतर होगा, इसलिए यह केवल एक बार बनाया जाता है।
आर्टब्रिस्टल

7
@artbristol, धन्यवाद! मैं नए एक्जिक्यूसर (हम जो आप हमारे कोड में सुझाव देते हैं) पर असहमत नहीं हैं। मूल उत्तर लिखने में, मैं मूल टुकड़े के लिए न्यूनतम कोड एनालागस लिखने की कोशिश कर रहा था। हमें उम्मीद है कि इन उत्तरों के कई पाठकों ने उन्हें कूद अंक के रूप में उपयोग किया। मैं javadoc के लिए एक प्रतिस्थापन लिखने की कोशिश नहीं कर रहा हूँ। मैं इसके लिए प्रभावी रूप से विपणन सामग्री लिख रहा हूं: यदि आपको यह विधि पसंद है, तो आपको उन सभी अन्य महान चीजों को देखना चाहिए जो हमें पेश करनी हैं ...!
बॉब क्रॉस

3
मुझे पता है कि मैं इस पर थोड़ी देर से टिप्पणी कर रहा हूं, लेकिन FutureTaskसीधे तौर पर काम करना आम तौर पर ऐसा नहीं है जो आप करना चाहते हैं। ExecutorServices Futureआपके लिए उपयुक्त बनाएगा जब आप उनके लिए submitRunnable/ Callable। इसी तरह से ScheduledExecutorServiceएस और ScheduledFutureजब आप scheduleRunnable/ के लिए Callable
पॉवरलॉर्ड

3
@Powerlord, मेरा उद्देश्य कोड के टुकड़े करना था जो ओपी के जितना संभव हो उतना निकट से मेल खाता था। मैं मानता हूं कि नया FutureTask इष्टतम नहीं है, लेकिन स्पष्टीकरण के प्रयोजनों के लिए यह स्पष्ट है।
बॉब क्रॉस

257

कहानी का नैतिक:

यदि आप कुछ व्यवहार को ओवरराइड करना चाहते हैं तो केवल इनहेरिट करें।

या इसके बजाय इसे पढ़ा जाना चाहिए:

इनहेरिट कम, इंटरफ़ेस अधिक।


1
यह हमेशा सवाल होना चाहिए कि क्या आप समवर्ती चल रही वस्तु बनाना शुरू करते हैं! क्या आपको भी थ्रेड ऑब्जेक्ट funtions की आवश्यकता है?
लिबर्टी

4
जब थ्रेड से विरासत में मिला है, एक लगभग हमेशा run()विधि के व्यवहार को ओवरराइड करना चाहता है ।
वारेन ड्यू

1
आप एक के व्यवहार को ओवरराइड नहीं कर सकते java.lang.Threadअधिभावी द्वारा run()विधि। उस स्थिति में आपको start()मेरे द्वारा बताई गई विधि को ओवरराइड करने की आवश्यकता है । आम तौर पर आप java.lang.Threadअपने निष्पादन ब्लॉक को run()विधि में इंजेक्ट करके केवल व्यवहार का पुन: उपयोग करते हैं ।
sura2k

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

232

खैर इतने अच्छे उत्तर, मैं इस पर और अधिक जोड़ना चाहता हूं। इससे समझने में मदद मिलेगी Extending v/s Implementing Thread
दो क्लास की फाइलों को बहुत बारीकी से बांधता है और कोड से निपटने के लिए कुछ बहुत मुश्किल पैदा कर सकता है।

दोनों दृष्टिकोण समान काम करते हैं लेकिन कुछ मतभेद रहे हैं।
सबसे आम अंतर है

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

हालाँकि, Runnable को लागू करने और थ्रेड को विस्तारित करने के बीच एक महत्वपूर्ण अंतर यह है कि
by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

निम्नलिखित उदाहरण आपको अधिक स्पष्ट रूप से समझने में मदद करेगा

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use the above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

उपरोक्त कार्यक्रम का आउटपुट।

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

रननेबल इंटरफ़ेस दृष्टिकोण में, एक वर्ग का केवल एक उदाहरण बनाया जा रहा है और इसे विभिन्न थ्रेड्स द्वारा साझा किया गया है। इसलिए प्रत्येक और हर थ्रेड पहुंच के लिए काउंटर का मूल्य बढ़ाया जाता है।

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

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

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

अधिकांश मामलों में, Runnable इंटरफ़ेस का उपयोग किया जाना चाहिए यदि आप केवल run()विधि को ओवरराइड करने की योजना बना रहे हैं और कोई अन्य थ्रेड विधियाँ नहीं हैं। यह महत्वपूर्ण है क्योंकि वर्गों को तब तक उप-वर्गित नहीं किया जाना चाहिए जब तक कि प्रोग्रामर वर्ग के मौलिक व्यवहार को संशोधित करने या बढ़ाने पर निर्भर न हो।

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

मुझे उम्मीद है कि इससे सहायता मिलेगी!


40
आपका कोड गलत है। मेरा मतलब है, यह वही करता है जो यह करता है, लेकिन वह नहीं जो आप दिखाने का इरादा रखते हैं।
ज़ीरो

38
स्पष्ट करने के लिए: रन करने योग्य मामले के लिए आपने एक ही इम्प्लिमेंट्स का उपयोग किया है एक से अधिक थ्रेड्स शुरू करने के लिए अप्रत्यक्ष उदाहरण, जबकि थ्रेड केस के लिए आप अलग-अलग एक्सटेंड्रेड इंस्टेंसेस बना रहे हैं जो स्पष्ट रूप से आपके द्वारा दिखाए गए व्यवहार की ओर ले जाते हैं। आपकी मुख्य विधि का दूसरा भाग निम्न होना चाहिए: ExtendsThread et = new ExtendsThread(); Thread tc1 = new Thread(et); tc1.start(); Thread.sleep(1000); Thread tc2 = new Thread(et); tc2.start(); Thread.sleep(1000); Thread tc3 = new Thread(et); tc3.start(); क्या यह कोई स्पष्ट है?
zEro

19
मैं अभी तक आपके इरादे को नहीं समझता, लेकिन मेरी बात यह थी कि यदि आप एक्सटेंड्रेड के कई उदाहरण बनाते हैं - तो वे सभी 1 लौटेंगे (जैसा आपने दिखाया है)। आप एक ही काम करके Runnable के लिए एक ही परिणाम प्राप्त कर सकते हैं, यानी ImplementsRunnable के कई उदाहरण बना सकते हैं।
ज़ीरो

3
@zEro हाय, मैं भविष्य से हूँ। यह देखते हुए कि आपके कोड के संस्करण में भी Threadवृद्धि हुई है, क्या यह कथन by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instanceगलत है? यदि नहीं, तो ऐसा कौन सा मामला है जो यह प्रदर्शित करता है?
ईविल वॉशिंग मशीन

4
यहां पोस्ट किया गया कोड भ्रामक है और इससे सिरदर्द हो सकता है। इसे साफ़ करने के लिए @zEro को धन्यवाद।
निकोस

78

एक बात जो मुझे आश्चर्य है कि अभी तक इसका उल्लेख नहीं किया गया है कि कार्यान्वयन Runnableआपकी कक्षा को अधिक लचीला बनाता है।

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


6
ठीक है, आप वास्तव में एक Threadवस्तु के साथ भी ऐसा ही कर सकते हैं क्योंकि Thread implements Runnable... ;-) लेकिन यह "बेहतर" लगता है कि एक Runnableसे उन्हें करने की तुलना में यह काम कर रहे हैं Thread!
21

7
यह सच है, लेकिन Threadइसमें बहुत सारे अतिरिक्त सामान शामिल हैं जिनकी आपको आवश्यकता नहीं है, और कई मामलों में नहीं चाहिए। आप हमेशा उस इंटरफ़ेस को लागू करना बेहतर समझते हैं जो वास्तव में आप कर रहे हैं से मेल खाता है।
हर्मिस

74

यदि आप किसी अन्य वर्ग को लागू करना चाहते हैं या Runnableउसका विस्तार करना चाहते हैं तो इंटरफ़ेस सबसे बेहतर है, अन्यथा, यदि आप नहीं चाहते हैं कि कोई अन्य वर्ग विस्तार या कार्यान्वित करे तो Threadवर्ग बेहतर है।

सबसे आम अंतर है

यहां छवि विवरण दर्ज करें

जब आप extends Thread क्लास करते हैं, उसके बाद आप किसी अन्य क्लास को नहीं बढ़ा सकते हैं, जिसकी आपको आवश्यकता है। (जैसा कि आप जानते हैं, जावा एक से अधिक वर्ग को इनहेरिट करने की अनुमति नहीं देता है)।

जब आप implements Runnable, आप भविष्य में या अब किसी भी अन्य वर्ग का विस्तार करने के लिए अपनी कक्षा के लिए स्थान बचा सकते हैं।

  • जावा कई उत्तराधिकारियों का समर्थन नहीं करता है, जिसका अर्थ है कि आप केवल जावा में एक वर्ग का विस्तार कर सकते हैं ताकि एक बार जब आप थ्रेड क्लास बढ़ाते हैं तो आपने अपना मौका खो दिया है और जावा में किसी अन्य वर्ग का विस्तार या विरासत नहीं कर सकता है।

  • ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, सामान्य रूप से एक क्लास का विस्तार करना, नई कार्यक्षमता जोड़ना, और व्यवहार को संशोधित करना या सुधारना शामिल है। यदि हम थ्रेड पर कोई संशोधन नहीं कर रहे हैं तो इसके बजाय रननेबल इंटरफ़ेस का उपयोग करें।

  • Runnable इंटरफ़ेस एक टास्क का प्रतिनिधित्व करता है जिसे सादे थ्रेड या एक्जिक्यूटर्स या किसी अन्य माध्यम से निष्पादित किया जा सकता है। थ्रेड की तुलना में रननेबल के रूप में टास्क का इतना तार्किक पृथक्करण एक अच्छा डिजाइन निर्णय है।

  • कार्य को रननेबल के रूप में अलग करने का अर्थ है कि हम कार्य का पुन: उपयोग कर सकते हैं और इसे विभिन्न माध्यमों से निष्पादित करने की स्वतंत्रता भी है। चूंकि आप एक थ्रेड को एक बार पूरा करने के बाद पुनः आरंभ नहीं कर सकते हैं। फिर से Runnable बनाम थ्रेड कार्य के लिए, Runnable विजेता है।

  • जावा डिजाइनर इसे पहचानता है और इसीलिए एक्जिक्यूटर्स रननेबल को टास्क के रूप में स्वीकार करता है और उनके पास वर्कर थ्रेड होता है जो उन कार्यों को अंजाम देता है।

  • सभी थ्रेड विधियों को इनहेरिट करना केवल एक टास्क का प्रतिनिधित्व करने के लिए अतिरिक्त ओवरहेड है जो रननेबल के साथ आसानी से किया जा सकता है।

Javarevisited.blogspot.com से सौजन्य

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

हालांकि, महत्वपूर्ण अंतर है।

जब आप extends Threadक्लास करते हैं, तो आपका प्रत्येक धागा एक अनोखी वस्तु बनाता है और उसके साथ जुड़ता है। जब आप implements Runnable, यह एक ही वस्तु को कई थ्रेड पर साझा करता है।


73

दरअसल, एक-दूसरे के साथ तुलना करना Runnableऔर समझदारी नहीं है Thread

यह दोनों Wheel and Engineमोटर वाहन के रिश्ते की तरह मल्टी-थ्रेडिंग में एक निर्भरता और संबंध है ।

मैं कहूंगा, दो चरणों के साथ मल्टी-थ्रेडिंग के लिए एक ही रास्ता है। मुझे अपनी बात कहने दो।

रन करने योग्य:
जब interface Runnableइसे लागू करने का मतलब है कि आप कुछ ऐसा बना रहे हैं जो run ableएक अलग धागे में है। अब एक ऐसी चीज का निर्माण करना जो एक थ्रेड के अंदर चल सके (एक थ्रेड के अंदर रन करने योग्य), थ्रेड बनाने का मतलब यह नहीं है।
तो कक्षा MyRunnableएक void runविधि के साथ एक साधारण वर्ग के अलावा कुछ भी नहीं है । और यह वस्तुएं केवल एक विधि के साथ कुछ सामान्य वस्तुएं runहोंगी जो सामान्य रूप से निष्पादित होने पर निष्पादित होंगी। (जब तक कि हम वस्तु को एक सूत्र में पास नहीं करते)।

थ्रेड:
class Thread मैं कहूंगा कि एक नया धागा शुरू करने की क्षमता वाला एक बहुत ही विशेष वर्ग जो वास्तव में अपनी start()विधि के माध्यम से बहु-सूत्रण को सक्षम बनाता है ।

तुलना करने के लिए बुद्धिमान क्यों नहीं?
क्योंकि हमें मल्टी-थ्रेडिंग के लिए दोनों की जरूरत है।

मल्टी-थ्रेडिंग के लिए हमें दो चीजों की आवश्यकता होती है:

  • कुछ ऐसा जो थ्रेड (रन करने योग्य) के अंदर चल सकता है।
  • कुछ ऐसा जो एक नया सूत्र (थ्रेड) शुरू कर सकता है।

तो तकनीकी और सैद्धांतिक रूप से दोनों को एक धागा शुरू करने के लिए आवश्यक है, एक चलेगा और एक इसे चलाएगा (जैसे Wheel and Engineमोटर वाहन)।

यही कारण है कि साथ तुम क्यों एक धागा शुरू नहीं कर सकते है MyRunnableआप का एक उदाहरण के लिए इसे पारित करने की जरूरत है Thread

लेकिन यह बना सकते हैं और एक धागा केवल का उपयोग कर चलाया जा सकता है class Threadक्योंकि कक्षा Threadलागू करता Runnableतो हम सभी जानते हैं Threadयह भी एक है Runnableअंदर।

अंत में Threadऔर Runnableमल्टीप्रेडिंग के लिए एक-दूसरे के पूरक हैं न कि प्रतिस्पर्धी या प्रतिस्थापन के लिए।


3
बिल्कुल सही! यह स्वीकृत उत्तर होना चाहिए। BTW मुझे लगता है कि सवाल संपादित किया गया है और ThreadAअब कोई मतलब नहीं है
idelvall

स्वीकृत उत्तर बहुत अधिक प्रत्यायोजित है धन्यवाद प्रतिक्रिया के लिए @idelvall
सैफ

सबसे अच्छा जवाब! धन्यवाद!
माइकलवाई

44

आपको रननेबल को लागू करना चाहिए, लेकिन अगर आप जावा 5 या उच्चतर पर चल रहे हैं, तो आपको इसे शुरू नहीं करना चाहिए, new Threadबल्कि इसके बजाय एक निष्पादन सेवा का उपयोग करना चाहिए। विवरण के लिए देखें: जावा में सरल थ्रेडिंग कैसे लागू करें


5
मुझे नहीं लगता कि ExecutorService उपयोगी होगा यदि आप सिर्फ एक ही धागा लॉन्च करना चाहते हैं।
पॉवरलॉर्ड

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

4
किसी भी मल्टी-थ्रेडिंग का उपयोग करने का क्या मतलब है अगर हम एपियर को जानते हैं कि यह एक एकल धागा होने जा रहा है। तो चलिए मान लेते हैं कि हमारे पास कई सूत्र हैं और यह उत्तर मूल्यवान है।
ज़ीरो

1
@zEro मुझे पूरा यकीन है कि एक कारण है कि केवल एक इवेंट डिस्पैच थ्रेड है। मुझे संदेह है कि यह एकमात्र ऐसा मामला है जिसके लिए एक अलग धागा होना सबसे अच्छा है, लेकिन संभवतः कई के लिए सबसे अच्छा नहीं है।
पोरकोसेफिनो

33

मैं एक विशेषज्ञ नहीं हूं, लेकिन मैं थ्रेड का विस्तार करने के बजाय रननेबल को लागू करने के एक कारण के बारे में सोच सकता हूं: जावा केवल एकल वंशानुक्रम का समर्थन करता है, इसलिए आप केवल एक वर्ग का विस्तार कर सकते हैं।

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


रनेबल में हम नेटवर्क कॉल नहीं कर सकते, क्या यह है? जैसा कि मैं android.os.NetworkOnMainThreadException कर रहा हूं। लेकिन थ्रेड का उपयोग करके मैं नेटवर्क कॉल कर सकता हूं। अगर मैं गलत हूं कृपया मुझे सही।
नबील थोबानी

@NabeelThobani सामान्य जावा परवाह नहीं करता है, लेकिन ऐसा लगता है कि Android करता है। मैं कहने के लिए Android के साथ पर्याप्त परिचित नहीं हूं, हालांकि।
पॉवरलॉर्ड

1
@NabeelThobani बेशक आप कर सकते हैं। संभवतः आप अपने Runnable के साथ एक थ्रेड नहीं बना रहे हैं।
m0skit0

20

मैं कहूंगा कि एक तीसरा तरीका है:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

हो सकता है कि यह मेरे हाल ही में जावास्क्रिप्ट और एक्टीस्क्रिप्ट 3 के भारी उपयोग से थोड़ा प्रभावित हो, लेकिन इस तरह से आपकी कक्षा को एक सुंदर अस्पष्ट इंटरफ़ेस लागू करने की आवश्यकता नहीं है Runnable


38
यह वास्तव में एक तीसरा तरीका नहीं है। आप अभी भी रननेबल को लागू कर रहे हैं, बस इसे गुमनाम रूप से कर रहे हैं।
डॉन रॉबी

2
@ डोन रॉबी: जो अलग है। यह अक्सर सुविधाजनक होता है, और आप फ़ील्ड और अंतिम स्थानीय चर का उपयोग कर सकते हैं जिसमें शामिल वर्ग / विधि है।
बार्ट वैन ह्युकेलोम

6
@BartvanHeukelom यह सुविधाजनक है, लेकिन अलग नहीं है। आप इसे किसी भी प्रकार के नेस्टेड क्लास, यानी इनर क्लास, लोकल क्लास और लैम्ब्डा एक्सप्रेशन के साथ कर सकते हैं।
xehpuk

18

जावा 8 के रिलीज के साथ, अब एक तीसरा विकल्प है।

Runnableएक कार्यात्मक इंटरफ़ेस है , जिसका अर्थ है कि इसके उदाहरण लंबोदर अभिव्यक्तियों या विधि संदर्भों के साथ बनाए जा सकते हैं।

आपके उदाहरण के साथ प्रतिस्थापित किया जा सकता है:

new Thread(() -> { /* Code here */ }).start()

या यदि आप एक ExecutorServiceऔर विधि संदर्भ का उपयोग करना चाहते हैं :

executor.execute(runner::run)

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


इस उत्तर को स्पष्टीकरण की आवश्यकता है। कुछ हैरान करने के बाद, मैं निष्कर्ष निकालता हूं कि () -> {}कस्टम तर्क का प्रतिनिधित्व करना है जिसे किसी की ज़रूरत है? तो क्या इसे बेहतर कहा जाएगा () -> { /* Code here */ }?
टूलमेकरसेव

17

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


12

यहां सभी को लगता है कि रननेबल को लागू करना एक रास्ता है और मैं वास्तव में उनसे असहमत नहीं हूं, लेकिन मेरी राय में थ्रेड को बढ़ाने का भी मामला है, वास्तव में आपने इसे अपने कोड में प्रदर्शित किया है।

यदि आप Runnable को लागू करते हैं तो Runnable को लागू करने वाले वर्ग का थ्रेड नाम पर कोई नियंत्रण नहीं है, यह कॉलिंग कोड है जो थ्रेड नाम सेट कर सकता है, जैसे:

new Thread(myRunnable,"WhateverNameiFeelLike");

लेकिन यदि आप थ्रेड का विस्तार करते हैं, तो आप इसे कक्षा में ही प्रबंधित करते हैं (जैसे आपके उदाहरण में आप थ्रेड 'थ्रेडबी' नाम देते हैं)। इस मामले में आप:

ए) डिबगिंग उद्देश्यों के लिए इसे अधिक उपयोगी नाम दे सकता है

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

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

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

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

अपने नाम के रूप में कॉलिंग स्टैक ट्रेस के साथ जेनेरिक थ्रेड का एक उदाहरण यहां दिया गया है:

public class DebuggableThread extends Thread {
    private static String getStackTrace(String name) {
        Throwable t= new Throwable("DebuggableThread-"+name);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        t.printStackTrace(ps);
        return os.toString();
    }

    public DebuggableThread(String name) {
        super(getStackTrace(name));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new Thread());
        System.out.println(new DebuggableThread("MainTest"));
    }
}

और यहाँ दो नामों की तुलना में उत्पादन का एक नमूना है:

Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
    at DebuggableThread.getStackTrace(DebuggableThread.java:6)
    at DebuggableThread.<init>(DebuggableThread.java:14)
    at DebuggableThread.main(DebuggableThread.java:19)
,5,main]

cHao तुम्हारी बात क्या है? आप थ्रेड्स के निर्माण का स्टैकट्रेस प्राप्त करने के लिए थ्रेड के निष्पादन के दौरान ऊपर दिए गए अपने कोड का उपयोग नहीं कर सकते हैं (इसके बजाय आप एक साधारण नाम प्राप्त करेंगे या थ्रेड लॉन्च का सबसे अच्छा स्टैकट्रेस), लेकिन थ्रेड को उप-वर्ग करके आप वास्तव में ऐसा कर सकते हैं और बाध्य कर सकते हैं यहां तक ​​कि आगे संदर्भ विशेष जानकारी की आवश्यकता होती है, जिससे आपको वास्तव में इस बात की अधिक ठोस समझ मिलती है कि कौन सा धागा एक मुद्दा हो सकता है।
एंटनीएम नोव

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

धागे का नाम? कुछ भी नहीं आप के रूप में अच्छी तरह से धागा वर्ग का विस्तार रोक रहा है।
रिची एचएच

11

चलने योग्य:

  • एक और वर्ग का विस्तार करने के लिए रननेबल कार्यान्वयन के लिए अधिक लचीलापन देता है
  • कोड को निष्पादन से अलग करता है
  • आपको थ्रेड पूल, ईवेंट थ्रेड या भविष्य में किसी अन्य तरीके से अपने रन करने योग्य को चलाने की अनुमति देता है।

यहां तक ​​कि अगर आपको अभी इसकी कोई आवश्यकता नहीं है, तो आप भविष्य में हो सकते हैं। चूंकि थ्रेड को ओवरराइड करने का कोई लाभ नहीं है, इसलिए रननेबल एक बेहतर उपाय है।


11

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

  1. आप आमतौर पर कार्यक्षमता जोड़ने या संशोधित करने के लिए एक वर्ग का विस्तार करते हैं। इसलिए, यदि आप किसी थ्रेड व्यवहार को अधिलेखित नहीं करना चाहते हैं , तो Runnable का उपयोग करें।

  2. एक ही प्रकाश में, अगर आप की जरूरत नहीं है करने के लिए इनहेरिट धागा तरीकों, आपको लगता है कि बिना कर सकते हैं भूमि के ऊपर Runnable का उपयोग करके।

  3. एकल वंशानुक्रम : यदि आप थ्रेड का विस्तार करते हैं तो आप किसी अन्य वर्ग से विस्तार नहीं कर सकते हैं, इसलिए यदि आपको ऐसा करने की आवश्यकता है, तो आपको Runnable का उपयोग करना होगा।

  4. ऐसा नहीं है कि इस अर्थ में यह एक Runnable काम है करने के लिए बेहतर है तकनीकी साधन से अलग डोमेन तर्क के लिए अच्छा डिजाइन है, अलग अपने से कार्य अपने धावक

  5. आप एक ही रन करने योग्य ऑब्जेक्ट को कई बार निष्पादित कर सकते हैं , एक थ्रेड ऑब्जेक्ट, हालांकि, केवल एक बार शुरू किया जा सकता है। (हो सकता है, कारण, क्यों अभियोजक Runnables स्वीकार करते हैं, लेकिन धागे नहीं।)

  6. यदि आप अपने कार्य को रननेबल के रूप में विकसित करते हैं, तो आपके पास सभी लचीलेपन हैं कि इसे अभी और भविष्य में कैसे उपयोग किया जाए । आप इसे एक्सक्यूसर्स के माध्यम से लेकिन थ्रेड के माध्यम से भी चला सकते हैं। और आप अभी भी इसे गैर-समवर्ती रूप से उसी धागे के भीतर किसी अन्य सामान्य प्रकार / वस्तु के रूप में उपयोग / कॉल कर सकते हैं।

  7. इससे आपके यूनिट परीक्षणों में कार्य-तर्क और संगामिति पहलुओं को अलग करना आसान हो जाता है

  8. यदि आप इस प्रश्न में रुचि रखते हैं, तो आप Callable और Runnable के बीच के अंतर में भी दिलचस्पी ले सकते हैं ।


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


8

यह Oracle के परिभाषित और एक थ्रेड ट्यूटोरियल शुरू करने पर चर्चा की गई है :

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

दूसरे शब्दों में, क्रियान्वयन Runnableउन परिदृश्यों में काम करेगा जहाँ आपकी कक्षा के अलावा एक वर्ग का विस्तार होता है Thread। जावा कई विरासत का समर्थन नहीं करता है। साथ ही, Threadउच्च-स्तरीय थ्रेड प्रबंधन API में से कुछ का उपयोग करते समय विस्तार करना संभव नहीं होगा। एकमात्र परिदृश्य जहां विस्तार हो रहा Threadहै, वह एक छोटे से अनुप्रयोग में है जो भविष्य में अपडेट के अधीन नहीं होगा। इसे लागू करना लगभग हमेशा बेहतर होता है Runnableक्योंकि यह अधिक लचीला होता है क्योंकि आपकी परियोजना बढ़ती है। एक डिज़ाइन परिवर्तन का बड़ा प्रभाव नहीं पड़ेगा क्योंकि आप जावा में कई इंटरफेस लागू कर सकते हैं, लेकिन केवल एक वर्ग का विस्तार कर सकते हैं।


8

सबसे सरल स्पष्टीकरण यह होगा कि Runnableहम एक ही वस्तु को कई थ्रेड्स पर असाइन कर सकते हैं और प्रत्येक Threadशेयर एक ही ऑब्जेक्ट स्टेट्स और व्यवहार को साझा कर सकते हैं।

उदाहरण के लिए, दो धागे, देखते हैं लगता है thread1 एक सरणी में डालता है एक पूर्णांक और thread2 जब सरणी भरा है सरणी से पूर्णांकों लेता है। ध्यान दें कि थ्रेड 2 को काम करने के लिए इसे सरणी की स्थिति को जानना होगा, चाहे थ्रेड 1 ने इसे भरा हो या नहीं।

कार्यान्वित Runnableकरने से आपको ऑब्जेक्ट साझा करने के लिए यह लचीलापन मिलता है जबकि extends Threadआप प्रत्येक थ्रेड के लिए नई ऑब्जेक्ट बनाते हैं इसलिए थ्रेड 1 द्वारा किया गया कोई भी अद्यतन थ्रेड 2 में खो जाता है।


7

अगर मैं गलत नहीं हूं, तो यह कमोबेश इसी तरह का है

इंटरफ़ेस और अमूर्त वर्ग के बीच अंतर क्या है?

" इज़ ए " रिलेशन और इंटरफ़ेस प्रदान करता है "क्षमता है"।

पसंदीदा लागू करें चलाए जाने योग्य :

  1. यदि आपको थ्रेड क्लास का विस्तार नहीं करना है और थ्रेड एपीआई डिफ़ॉल्ट कार्यान्वयन को संशोधित करना है
  2. यदि आप आग लगा रहे हैं और कमांड भूल जाते हैं
  3. यदि आप पहले से ही किसी अन्य वर्ग का विस्तार कर रहे हैं

पसंद करें " थ्रेड का विस्तार ":

  1. यदि आपको इन थ्रेड तरीकों में से किसी को ओवरराइड करना है जैसा कि oracle प्रलेखन पृष्ठ में सूचीबद्ध है

आम तौर पर आपको थ्रेड व्यवहार को ओवरराइड करने की आवश्यकता नहीं होती है। इसलिए अधिकांश समय के लिए रननेबल को लागू किया जाता है।

एक अलग नोट पर, उन्नत ExecutorServiceया ThreadPoolExecutorServiceएपीआई का उपयोग करना अधिक लचीलापन और नियंत्रण प्रदान करता है।

इस एसई प्रश्न पर एक नजर:

ExecutorService बनाम आकस्मिक थ्रेड स्पैनर


5

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


5

ऐसा इसलिए है एस के ठोस एकल जिम्मेदारी:।

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

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

  1. आपके एप्लिकेशन में थ्रेड हैंडलिंग (यानी निष्पादन संदर्भ को क्वेरी करना और संशोधित करना)
  2. कोड के टुकड़े द्वारा कार्यान्वित एल्गोरिथ्म (रन करने योग्य भाग)

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

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

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


5

बेस क्लास का विस्तार करने के बजाय आप एक इंटरफ़ेस लागू करना चाहते हैं, वह यह है कि आप पहले से ही किसी अन्य वर्ग का विस्तार कर रहे हैं। आप केवल एक वर्ग का विस्तार कर सकते हैं, लेकिन आप किसी भी संख्या में इंटरफेस को लागू कर सकते हैं।

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


हाँ, Runnable इंटरफ़ेस को लागू करने के लिए किसी भी वर्ग का विस्तार करके अपने स्वयं के तर्क को लागू करने के लिए स्वतंत्र हैं, यही कारण है कि Runnable ज्यादातर थ्रेड वर्ग पर पसंद किया जाता है।
आकाश ५२ Ak Ak

5

यदि आप रनवेबल का उपयोग करते हैं तो आप अपने किसी भी अन्य वर्ग का विस्तार करने के लिए स्थान बचा सकते हैं।


5

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

अगर यह पूरा उद्देश्य है, तो मुझे एक विशेष थ्रेड की आवश्यकता कहां है। इसे सिस्टम के थ्रेड पूल से RAW थ्रेड उठाकर पूरा किया जा सकता है और इसे हमारा कार्य (हमारी कक्षा का एक उदाहरण) कहा जा सकता है।

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

हमें एक कार्य की आवश्यकता है, इसलिए एक कार्य परिभाषा लिखें जो थ्रेड पर चलाई जा सकती है। इसलिए Runnable का उपयोग करें।

हमेशा याद रखें implementsकि विशेष रूप से एक व्यवहार प्रदान करने के लिए उपयोग किया जाता है और extendsएक सुविधा / संपत्ति प्रदान करने के लिए उपयोग किया जाता है।

हम थ्रेड की संपत्ति नहीं चाहते हैं, इसके बजाय हम चाहते हैं कि हमारी कक्षा एक कार्य के रूप में व्यवहार करे जो चलाया जा सकता है।


4

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


4

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


4

जावा कई विरासत का समर्थन नहीं करता है, इसलिए यदि आप थ्रेड क्लास का विस्तार करते हैं, तो किसी अन्य वर्ग को नहीं बढ़ाया जाएगा।

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


4

Runnableएक इंटरफ़ेस है, जबकि Threadएक वर्ग है जो इस इंटरफ़ेस को लागू करता है। एक डिज़ाइन बिंदु से, किसी कार्य को कैसे परिभाषित किया जाता है और इसे कैसे निष्पादित किया जाता है, के बीच एक स्वच्छ अलगाव होना चाहिए। पूर्व एक Runnalbeकार्यान्वयन की जिम्मेदारी है , और बाद वाला Threadवर्ग का काम है । लागू होने के अधिकांश मामलों में Runnableपालन ​​करने का सही तरीका है।


4

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

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


4

यहां मेरे दो सेंट जोड़ना - हमेशा जब भी संभव हो उपयोग करें implements Runnable। नीचे दो चेतावनी दी गई है कि आपको extends Threadएस का उपयोग क्यों नहीं करना चाहिए

  1. आदर्श रूप से आपको थ्रेड क्लास का विस्तार कभी नहीं करना चाहिए; Threadवर्ग बनाया जाना चाहिए final। कम से कम इसके तरीके जैसे thread.getId()। विस्तार से संबंधित बग के लिए इस चर्चा को देखें Thread

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

कृपया http://pastebin.com/BjKNNs2G देखें ।

public class WaitPuzzle {

    public static void main(String[] args) throws InterruptedException {
        DoNothing doNothing = new DoNothing();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        new WaitForever(doNothing).start();
        Thread.sleep(100);
        doNothing.start();
        while(true) {
            Thread.sleep(10);
        }
    }


    static class WaitForever extends  Thread {

        private DoNothing doNothing;

        public WaitForever(DoNothing doNothing) {
            this.doNothing =  doNothing;
        }

        @Override
        public void run() {
            synchronized (doNothing) {
                try {
                    doNothing.wait(); // will wait forever here as nobody notifies here
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unreachable Code");
            }
        }
    }

    static class DoNothing extends Thread {

        @Override
        public void run() {
            System.out.println("Do Nothing ");
        }
    } 
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.