আমি কীভাবে একটি জাভা থ্রেডে একটি পরামিতি পাস করতে পারি?


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
@ জেসনম না, এটি কনস্ট্রাক্টর - কনস্ট্রাক্টরের কোনও রিটার্ন টাইপ নেই।
Alnitak

এর অর্থ এটি ব্যবহার করে নির্মিত প্রতিটি থ্রেডের rএকই আর্গুমেন্ট থাকবে, সুতরাং আমরা যদি একাধিক থ্রেডে চলমান বিভিন্ন আর্গুমেন্টটি পাস MyThreadকরতে চাই তবে MyThreadপ্রতিটি থ্রেডের জন্য কাঙ্ক্ষিত যুক্তি ব্যবহার করে আমাদের একটি নতুন উদাহরণ তৈরি করা দরকার create অন্য কথায়, একটি থ্রেড আপ এবং চলমান পেতে আমাদের দুটি বস্তু তৈরি করতে হবে: থ্রেড এবং মাই থ্রেড। এটাকে কী খারাপ, কর্মক্ষমতা অনুযায়ী বিবেচনা করা হবে?
আইজাক ক্লিনম্যান 21

2
@ ইসাকাক্লেইনম্যান ভাল, আপনি যেভাবেই থ্রেড প্রসারিত না করেন, আপনাকে তা করতে হবে। এবং এই সমাধানটি এখনও সেই ক্ষেত্রে কাজ করে - কেবল "চালিতযোগ্য" প্রয়োগ করে "থ্রেড প্রসারিত করে", "চলমান" থেকে "থ্রেড" এবং "নতুন থ্রেড (আর)" থেকে "আর" পরিবর্তন করুন।
ব্যবহারকারী 253751

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();

থ্রেড বিটিডাব্লুয়ের চেয়ে রান্নেবল একটি আরও ভাল সমাধান। সুতরাং আমি পছন্দ করব:

   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()pparameterp
র্যান্ডল কুক

আমি মনে করি আপনি )প্রথম উদাহরণটিতে একটি মিস করছেন
হ্যাক-আর

অজ্ঞাতনামা শ্রেণীর জন্য @ র্যান্ডলকুকের মতো আমারও একই অভিজ্ঞতা ছিল। যতক্ষণ final X parameterনা new Runnable()লাইনের আগে আমার কাছে ছিল তখন আমি parameterভিতরে প্রবেশ করতে পারতাম run()। আমার অতিরিক্ত করার দরকার পড়েনি p = parameter
উইসবাকী

finalএটি আর গুরুত্বপূর্ণ নয়; পরিবর্তনশীল কার্যকরভাবে চূড়ান্ত হলে এটি যথেষ্ট (যদিও এটির কোনও ক্ষতি না হলেও)
ব্যবহারকারী 85421

43

একটি চলমান বা থ্রেড শ্রেণীর নির্মাণকারীর মাধ্যমে

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?
তুষার 21

@ জানুন যে @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পদ্ধতির স্বাক্ষর কী হবে তা আপনার উপর নির্ভর করে (সুতরাং এটি আরও এবং / অথবা বিভিন্ন যুক্তি লাগতে পারে) এবং অবশ্যই এর নামও, তবে মূলত আপনি একটি ধারণা পাবেন get

প্রকৃতপক্ষে ব্লক ব্যবহার করে বেনাম শ্রেণিতে একটি প্যারামিটার পাশ করার আরও একটি উপায় রয়েছে। এই বিবেচনা:

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

সত্য, প্যারামিটারে সেটার এবং সমস্ত অ্যাক্সেস সিঙ্ক্রোনাইজ করা উচিত।
jwoolard

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 জাভাডোকসও দেখুন ।


শেষ পর্যন্ত একটি উপায় those বিরক্তিকর ক্ষেত্রগুলি ছাড়া এটি করার। এখন আমার জাভা 8 এ আপগ্রেড করার জন্য আমার অপেক্ষা করতে হবে
শ্রীধর সারনোবাত

5

আমি জানি যে আমি কয়েক বছর দেরি করে এসেছি, তবে আমি এই সমস্যাটি নিয়ে এসে একটি অপ্রথাবাদী পদ্ধতি গ্রহণ করেছি took আমি একটি নতুন ক্লাস না করে এটি করতে চেয়েছিলাম, তাই এটিই আমি নিয়ে এসেছি:

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

আপনি রান্নেবল থেকে ক্লাস অর্জন করতে পারেন এবং নির্মাণের সময় (বলুন) প্যারামিটারটি পাস করুন।

তারপরে এটি থ্রেড.স্টার্ট (চলমান r) ব্যবহার করে চালু করুন;

আপনি কি এটি বলতে পারেন থাকাকালীন থ্রেড চলমান হয়, তাহলে কেবল কল থ্রেড আপনার উদ্ভূত বস্তুর একটি রেফারেন্স ধরে রাখুন, এবং কল উপযুক্ত সেটার পদ্ধতি (সিঙ্ক্রোনাইজ যেখানে যথাযথ)


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

আরও একটি বিকল্প; এই পদ্ধতির সাহায্যে আপনি অ্যাসিঙ্ক্রোনাস ফাংশন কলের মতো রান রানযোগ্য আইটেমটি ব্যবহার করতে পারবেন। যদি আপনার কার্যটির কোনও ফলাফল ফেরত দেওয়ার প্রয়োজন না হয়, যেমন এটি কিছু কর্ম সম্পাদন করে তবে কীভাবে আপনি "ফলাফল" পাস করবেন সে সম্পর্কে আপনাকে চিন্তা করার দরকার নেই।

এই প্যাটার্নটি আপনাকে একটি আইটেম পুনরায় ব্যবহার করতে দেয় যেখানে আপনার কোনও ধরণের অভ্যন্তরীণ অবস্থার প্রয়োজন। কনস্ট্রাক্টর কেয়ারে প্যারামিটার (গুলি) পাস না করার সময় প্রোগ্রামগুলির প্যারামিটারগুলিতে অ্যাক্সেসের মধ্যস্থতা করার প্রয়োজন হয়। আপনার ব্যবহারের ক্ষেত্রে বিভিন্ন কলার ইত্যাদি জড়িত থাকলে আপনার আরও চেকের প্রয়োজন হতে পারে You

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 );
      }

  }

}

থ্রেড টি = নতুন থ্রেড (নতুন মাইআরনেবল (পরামিতি)); t.start ();

আপনার যদি প্রক্রিয়াজাতকরণের ফলাফলের প্রয়োজন হয় তবে সাব-টাস্ক শেষ হয়ে গেলে আপনাকে MyRunnable এর সমাপ্তির সমন্বয়ও করতে হবে। আপনি কোনও কলটি পাস করতে পারেন বা কেবল থ্রেড 'টি' ইত্যাদির জন্য অপেক্ষা করতে পারেন etc.


1

বিশেষ করে অ্যান্ড্রয়েডের জন্য

কলব্যাকের উদ্দেশ্যে আমি সাধারণত 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"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.