मैं एक जावा थ्रेड के लिए एक पैरामीटर कैसे पारित कर सकता हूं?


290

क्या कोई मुझे सुझाव दे सकता है कि मैं एक पैरामीटर को एक धागे में कैसे पारित कर सकता हूं?

साथ ही, यह अनाम वर्गों के लिए कैसे काम करता है?


5
क्या आप इसके बारे में कुछ अतिरिक्त स्पष्टीकरण जोड़ना चाहेंगे? इसके लिए कई सारी तकनीकें हैं, लेकिन ये सभी अंतिम लक्ष्य पर निर्भर हैं।
आर्टेम बार्गर

4
क्या आप पहले से ही चल रहे धागे के लिए एक पैरामीटर पारित करने का मतलब है? क्योंकि सभी मौजूदा उत्तर नए थ्रेड्स को पारित करने के मापदंडों के बारे में हैं ...
वैलेंटाइन रोचर

अब आप उपयोग कर सकते हैं Consumer<T>
एलेक्स78191

जवाबों:


371

आपको रनवेबल ऑब्जेक्ट में कंस्ट्रक्टर में पैरामीटर पास करना होगा:

public class MyRunnable implements Runnable {

   public MyRunnable(Object parameter) {
       // store parameter for later user
   }

   public void run() {
   }
}

और इसे इस तरह से आह्वान करें:

Runnable r = new MyRunnable(param_value);
new Thread(r).start();

7
@ajonm नहीं, यह एक कंस्ट्रक्टर है - कंस्ट्रक्टर्स के पास रिटर्न टाइप नहीं है।
अलनीतक

इसका अर्थ है कि उपयोग किए गए प्रत्येक थ्रेड rमें एक ही तर्क होगा, इसलिए यदि हम कई थ्रेड्स के लिए विभिन्न तर्क पास करना चाहते हैं, तो हमें प्रत्येक थ्रेड के लिए वांछित तर्क का उपयोग करके MyThreadएक नया MyThreadउदाहरण बनाने की आवश्यकता होगी । दूसरे शब्दों में, एक धागा ऊपर और चलाने के लिए हमें दो ऑब्जेक्ट बनाने की आवश्यकता है: थ्रेड और MyThread। क्या इसे बुरा माना जाता है, प्रदर्शन-वार?
इसहाक क्लेनमैन

2
@IsaacKleinman अच्छी तरह से, आपको वैसे भी करना होगा, जब तक कि आप थ्रेड का विस्तार नहीं करते। और यह समाधान अभी भी उस मामले में काम करता है - बस "इम्प्लीमेंट रनवेबल" को "थ्रेड", "रननेबल" से "थ्रेड", और "न्यू थ्रेड (आर)" से "आर" में बदल दें।
user253751

111

बेनामी वर्गों के लिए:

सवाल संपादन के जवाब में यहाँ बताया गया है कि यह बेनामी वर्गों के लिए कैसे काम करता है

   final X parameter = ...; // the final is important
   Thread t = new Thread(new Runnable() {
       p = parameter;
       public void run() { 
         ...
       };
   t.start();

नामित कक्षाएं:

आपके पास एक वर्ग है जो थ्रेड (या रननेबल को लागू करता है) और एक निर्माता है जिसमें आप पास करना चाहते हैं। फिर, जब आप नया थ्रेड बनाते हैं, तो आपको तर्कों में पास होना होता है, और फिर थ्रेड शुरू होता है, कुछ इस तरह से:

Thread t = new MyThread(args...);
t.start();

Runnable थ्रेड BTW की तुलना में बहुत बेहतर समाधान है। तो मैं पसंद करूंगा:

   public class MyRunnable implements Runnable {
      private X parameter;
      public MyRunnable(X parameter) {
         this.parameter = parameter;
      }

      public void run() {
      }
   }
   Thread t = new Thread(new MyRunnable(parameter));
   t.start();

यह उत्तर मूल रूप से इस समान प्रश्न के समान है: थ्रेड ऑब्जेक्ट में पैरामीटर कैसे पास करें


2
मेरे पास आपके अनाम वर्ग उदाहरण के समान कोड है, सिवाय इसके कि मैं किसी क्षेत्र का उपयोग किए बिना parameterसीधे run()विधि से पहुंचता हूं p। यह काम करने लगता है। क्या पहले से नकल न करके कुछ सूक्ष्म बहुमूल्‍य चीज मुझे याद आ रही parameterहै p?
रान्डेल कुक

मुझे लगता है कि आप )पहले उदाहरण में
हैक

मुझे अनाम श्रेणी के लिए @RandallCook जैसा ही अनुभव था। जब तक मेरे पास लाइन final X parameterसे पहले new Runnable()था, तब तक मैं parameterअंदर पहुंच सकता था run()। मुझे अतिरिक्त करने की आवश्यकता नहीं थी p = parameter
वारबैंक

finalक्या यह उतना महत्वपूर्ण नहीं है; यह पर्याप्त है अगर चर प्रभावी रूप से अंतिम है (इसके बावजूद इसका कोई नुकसान नहीं हुआ है)
user85421

43

एक Runnable या थ्रेड वर्ग के निर्माता के माध्यम से

class MyThread extends Thread {

    private String to;

    public MyThread(String to) {
        this.to = to;
    }

    @Override
    public void run() {
        System.out.println("hello " + to);
    }
}

public static void main(String[] args) {
    new MyThread("world!").start();
}

5
+1 यह दिखाने के लिए कि रननेबल को लागू करने के बजाय थ्रेड का विस्तार कैसे किया जाए।
Caelum

1
हमें इसकी आवश्यकता क्यों है @Override?
बर्फ

@ @Overrideस्पष्ट रूप से बताएं कि यह थ्रेड क्लास में अमूर्त पद्धति को ओवरराइड कर रहा है।
विस्कोज

22

यह उत्तर बहुत देर से आता है, लेकिन शायद कोई इसे उपयोगी पाएगा। यह Runnableनामांकित वर्ग (इनलाइनर्स के लिए आसान) घोषित किए बिना एक पैरामीटर (रों) पास करने के बारे में है :

String someValue = "Just a demo, really...";
new Thread(new Runnable() {
    private String myParam;
    public Runnable init(String myParam) {
        this.myParam = myParam;
        return this;
    }
    @Override
    public void run() {
        System.out.println("This is called from another thread.");
        System.out.println(this.myParam);
    }
}.init(someValue)).start();

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

वास्तव में एक ब्लॉक करने के लिए अनाम ब्लॉक के उपयोग के साथ एक अनाम वर्ग को एक पैरामीटर पारित करने का एक और तरीका भी है। इस पर विचार करो:

String someValue = "Another demo, no serious thing...";
int anotherValue = 42;

new Thread(new Runnable() {
    private String myParam;
    private int myOtherParam;
    {
        this.myParam = someValue;
        this.myOtherParam = anotherValue;
    }
    @Override
    public void run() {
        System.out.println("This comes from another thread.");
        System.out.println(this.myParam + ", " + this.myOtherParam);
    }
}).start();

तो सभी इनिशियलाइज़र ब्लॉक के अंदर होता है।


मुझे वास्तव में यह आखिरी उदाहरण काफी पसंद आया। बाहरी दायरे में चर को संदर्भित करने के लिए जेएस में एक बंद का उपयोग करने की याद दिलाता है। लेकिन क्या this.myParamवास्तव में आवश्यक है? क्या आप केवल निजी चर नहीं छोड़ सकते और बाहरी दायरे से चर का संदर्भ ले सकते हैं? मैं समझता हूं (निश्चित रूप से) इसके कुछ निहितार्थ हैं, जैसे कि धागा शुरू होने के बाद परिवर्तन के लिए खुला होना।
ऑलिगॉफ़ेन

@ जेफे ने वास्तव में नीचे दिए गए उत्तर में इसका जवाब दिया!
ऑलिगॉफ़ेन

17

जब आप एक धागा बनाते हैं, तो आपको एक उदाहरण की आवश्यकता होती है Runnable। एक पैरामीटर में पास करने का सबसे आसान तरीका यह होगा कि इसे कंस्ट्रक्टर के तर्क के रूप में पास किया जाए:

public class MyRunnable implements Runnable {

    private volatile String myParam;

    public MyRunnable(String myParam){
        this.myParam = myParam;
        ...
    }

    public void run(){
        // do something with myParam here
        ...
    }

}

MyRunnable myRunnable = new myRunnable("Hello World");
new Thread(myRunnable).start();

यदि आप तब पैरामीटर बदलना चाहते हैं जब थ्रेड चल रहा है, तो आप बस अपनी रन करने योग्य कक्षा में एक सेटर विधि जोड़ सकते हैं:

public void setMyParam(String value){
    this.myParam = value;
}

एक बार जब आपके पास यह हो जाए, तो आप इस तरह कॉल करके पैरामीटर का मान बदल सकते हैं:

myRunnable.setMyParam("Goodbye World");

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


1
एक सेटर को जोड़ने से संभावित दौड़ की स्थिति नहीं बनती है? यदि थ्रेड एक मान के रूप में चर के साथ शुरू होता है, लेकिन सेटर इसे बदल देता है तो मध्य-निष्पादन समस्याग्रस्त नहीं होगा?
anon58192932

सच है, सेटर और पैरामीटर तक सभी पहुंच को सिंक्रनाइज़ किया जाना चाहिए।
जूलार्ड

9

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

class MyThread implements Runnable{
   private int a;
   private String b;
   private double c;

   public MyThread(int a, String b, double c){
      this.a = a;
      this.b = b;
      this.c = c;
   }

   public void run(){
      doSomething(a, b, c);
   }
}

8

आप या तो विस्तार कर सकते हैं या और पैरामीटर प्रदान के रूप में आप चाहते हैं। डॉक्स में सरल उदाहरण हैं । मैं उन्हें यहाँ पोर्ट करूँगा:Thread classRunnable class

 class PrimeThread extends Thread {
     long minPrime;
     PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }

 PrimeThread p = new PrimeThread(143);
 p.start();

 class PrimeRun implements Runnable {
     long minPrime;
     PrimeRun(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }


 PrimeRun p = new PrimeRun(143);
 new Thread(p).start();

7

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


6

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

final String param1 = "First param";
final int param2 = 2;
new Thread(() -> {
    // Do whatever you want here: param1 and param2 are in-scope!
    System.out.println(param1);
    System.out.println(param2);
}).start();

5

जावा 8 में आप सीधे कंसीडर एपीआई और थ्रेड के साथ काम करने के लिए उच्च स्तर के प्रतिस्थापन के रूप में lambdaअभिव्यक्ति का उपयोग कर सकते हैं :ExecutorService

newCachedThreadPool()एक थ्रेड पूल बनाता है जो आवश्यकतानुसार नए थ्रेड बनाता है, लेकिन जब वे उपलब्ध होते हैं तो पहले निर्मित थ्रेड का फिर से उपयोग करेंगे। ये पूल आम तौर पर उन कार्यक्रमों के प्रदर्शन में सुधार करेंगे जो कई अल्पकालिक अतुल्यकालिक कार्यों को निष्पादित करते हैं।

    private static final ExecutorService executor = Executors.newCachedThreadPool();

    executor.submit(() -> {
        myFunction(myParam1, myParam2);
    });

executors Javadocs भी देखें ।


अंत में उन कष्टप्रद क्षेत्रों के बिना इसे करने का एक तरीका। अब मुझे सिर्फ जावा 8. पर अपग्रेड करने के लिए अपने उत्पाद की प्रतीक्षा करने की आवश्यकता है।
श्रीधर सरनोबत

5

मुझे पता है कि मुझे कुछ साल देर हो गई है, लेकिन मैं इस मुद्दे पर आया और एक अपरंपरागत दृष्टिकोण लिया। मैं इसे एक नई कक्षा बनाये बिना करना चाहता था, इसलिए यह वही है जिसके साथ मैं आया:

int x = 0;
new Thread((new Runnable() {
     int x;
     public void run() {
        // stuff with x and whatever else you want
     }
     public Runnable pass(int x) {
           this.x = x;
           return this;
     }
}).pass(x)).start();

4

स्टार्ट () और रन () विधियों से गुजरता हुआ पैरामीटर:

// Tester
public static void main(String... args) throws Exception {
    ThreadType2 t = new ThreadType2(new RunnableType2(){
        public void run(Object object) {
            System.out.println("Parameter="+object);
        }});
    t.start("the parameter");
}

// New class 1 of 2
public class ThreadType2 {
    final private Thread thread;
    private Object objectIn = null;
    ThreadType2(final RunnableType2 runnableType2) {
        thread = new Thread(new Runnable() {
            public void run() {
                runnableType2.run(objectIn);
            }});
    }
    public void start(final Object object) {
        this.objectIn = object;
        thread.start();
    }
    // If you want to do things like setDaemon(true); 
    public Thread getThread() {
        return thread;
    }
}

// New class 2 of 2
public interface RunnableType2 {
    public void run(Object object);
}

3

आप रननेबल से एक वर्ग प्राप्त कर सकते हैं, और निर्माण के दौरान (कहते हैं) पैरामीटर को पास कर सकते हैं।

फिर इसे थ्रेड.स्टार्ट (रन करने योग्य आर) का उपयोग करके लॉन्च करें;

तुम्हारा मतलब हैं , जबकि धागा चल रहा है, तो बस बुला धागे में अपने व्युत्पन्न वस्तु के संदर्भ को पकड़, और कॉल उचित सेटर तरीकों (सिंक्रनाइज़ कर जहां उपयुक्त हो)


2

रनवे में मापदंडों को पारित करने का एक सरल तरीका है। कोड:

public void Function(final type variable) {
    Runnable runnable = new Runnable() {
        public void run() {
            //Code adding here...
        }
    };
    new Thread(runnable).start();
}

2

नहीं, आप इस run()पद्धति को पैरामीटर नहीं दे सकते । हस्ताक्षर आपको बताता है कि (इसका कोई पैरामीटर नहीं है)। संभवतः ऐसा करने का सबसे आसान तरीका एक उद्देश्य-निर्मित वस्तु का उपयोग करना होगा जो निर्माण में एक पैरामीटर लेता है और इसे अंतिम चर में संग्रहीत करता है:

public class WorkingTask implements Runnable
{
    private final Object toWorkWith;

    public WorkingTask(Object workOnMe)
    {
        toWorkWith = workOnMe;
    }

    public void run()
    {
        //do work
    }
}

//...
Thread t = new Thread(new WorkingTask(theData));
t.start();

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


1

एक और विकल्प; यह दृष्टिकोण आपको अतुल्यकालिक फ़ंक्शन कॉल की तरह Runnable आइटम का उपयोग करने देता है। यदि आपके कार्य को परिणाम वापस करने की आवश्यकता नहीं है, उदाहरण के लिए, यह सिर्फ कुछ कार्रवाई करता है तो आपको इस बारे में चिंता करने की आवश्यकता नहीं है कि आप "परिणाम" कैसे पास करते हैं।

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

public class MyRunnable implements Runnable 
{
  private final Boolean PARAMETER_LOCK  = false;
  private X parameter;

  public MyRunnable(X parameter) {
     this.parameter = parameter;
  }

  public void setParameter( final X newParameter ){

      boolean done = false;
      synchronize( PARAMETER_LOCK )
      {
          if( null == parameter )
          {
              parameter = newParameter;
              done = true;
          }
      }
      if( ! done )
      {
          throw new RuntimeException("MyRunnable - Parameter not cleared." );
      }
  }


  public void clearParameter(){

      synchronize( PARAMETER_LOCK )
      {
          parameter = null;
      }
  }


  public void run() {

      X localParameter;

      synchronize( PARAMETER_LOCK )
      {
          localParameter = parameter;
      }

      if( null != localParameter )
      {
         clearParameter();   //-- could clear now, or later, or not at all ...
         doSomeStuff( localParameter );
      }

  }

}

थ्रेड टी = नया थ्रेड (नया MyRunnable (पैरामीटर)); t.start ();

यदि आपको प्रसंस्करण के परिणाम की आवश्यकता है, तो आपको उप-कार्य पूरा होने पर MyRunnable के पूरा होने के समन्वय की भी आवश्यकता होगी। आप कॉल वापस पास कर सकते हैं या बस थ्रेड 't', आदि पर प्रतीक्षा कर सकते हैं।


1

विशेष रूप से Android के लिए

कॉलबैक उद्देश्यों के लिए, मैं आमतौर पर Runnableइनपुट पैरामीटर (एस) के साथ अपने स्वयं के सामान्य को लागू करता हूं :

public interface Runnable<TResult> {
    void run(TResult result);
}

उपयोग सरल है:

myManager.doCallbackOperation(new Runnable<MyResult>() {
    @Override
    public void run(MyResult result) {
        // do something with the result
    }
});

प्रबंधक में:

public void doCallbackOperation(Runnable<MyResult> runnable) {
    new AsyncTask<Void, Void, MyResult>() {
        @Override
        protected MyResult doInBackground(Void... params) {
            // do background operation
            return new MyResult(); // return resulting object
        }

        @Override
        protected void onPostExecute(MyResult result) {
            // execute runnable passing the result when operation has finished
            runnable.run(result);
        }
    }.execute();
}

1

अपनी कक्षा में एक स्थानीय चर बनाएं extends Threadया implements Runnable

public class Extractor extends Thread {
    public String webpage = "";
    public Extractor(String w){
        webpage = w;
    }
    public void setWebpage(String l){
        webpage = l;
    }

    @Override
    public void run() {// l is link
        System.out.println(webpage);
    }
    public String toString(){
        return "Page: "+webpage;
    }}

इस तरह, आप एक चर पास कर सकते हैं जब आप इसे चलाते हैं।

Extractor e = new Extractor("www.google.com");
e.start();

उत्पादन:

"www.google.com"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.