Как передать параметр в Java-поток?

Может кто-нибудь предложить мне, как я могу передать параметр в поток?

Также, как это работает для анонимных классов?

Ответ 1

Вам необходимо передать параметр в конструкторе в объект Runnable:

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

Ответ 2

Для анонимных классов:

В ответ на редактирование вопроса, вот как это работает для анонимных классов

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

Именованные классы:

У вас есть класс, который расширяет Thread (или реализует Runnable) и конструктор с параметрами, которые вы хотите передать. Затем, когда вы создаете новый поток, вам нужно передать аргументы, а затем запустить поток, что-то вроде этого:

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

Runnable - намного лучшее решение, чем Thread 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();

Этот ответ в основном такой же, как этот аналогичный вопрос: Как передать параметры объекту Thread

Ответ 3

через конструктор класса Runnable или Thread

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

Ответ 4

При создании потока вам понадобится экземпляр 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();

Если вы хотите изменить параметр во время работы потока, вы можете просто добавить метод setter к вашему runnable классу:

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

После этого вы можете изменить значение параметра, вызвав вот так:

myRunnable.setMyParam("Goodbye World");

Конечно, если вы хотите вызвать действие при изменении параметра, вам придется использовать блокировки, что значительно усложняет ситуацию.

Ответ 5

Этот ответ приходит очень поздно, но, возможно, кто-то найдет его полезным. Речь идет о том, как передать параметр в Runnable, даже не объявив именованный класс (удобный для inliners):

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

Таким образом, все происходит внутри блока инициализатора.

Ответ 6

Чтобы создать поток, вы обычно создаете собственную реализацию Runnable. Передайте параметры в поток в конструкторе этого класса.

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

Ответ 7

Вы можете либо расширить Thread class, либо Runnable class и предоставить параметры по своему усмотрению. В docs есть простые примеры. Я пошлю их сюда:

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

Ответ 8

Либо напишите класс, который реализует Runnable, и передайте все, что вам нужно, в подходящем конструкторе, или напишите класс, который расширяет Thread с соответствующим конструктором, который вызывает super() с соответствующими параметрами.

Ответ 9

Начиная с Java 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();

Ответ 10

Вы можете получить класс из Runnable, а во время построения (скажем) передать параметр в.

Затем запустите его с помощью Thread.start(Runnable r);

Если вы имеете в виду, пока поток работает, просто держите ссылку на свой производный объект в вызывающем потоке и вызовите соответствующие методы настройки (синхронизируя при необходимости)

Ответ 11

Передача параметров через методы start() и run():

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

Ответ 12

Существует простой способ передачи параметров в runnables. Код:

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

Ответ 13

В Java 8 вы можете использовать lambda выражения с API параллелизма и ExecutorService в качестве замены более высокого уровня для прямой работы с потоками:

newCachedThreadPool() Создает пул потоков, который при необходимости создает новые потоки, но будет использовать ранее newCachedThreadPool() потоки, когда они будут доступны. Эти пулы обычно улучшают производительность программ, выполняющих многие недолговечные асинхронные задачи.

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

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

См. Также executors javadocs.

Ответ 14

Еще один вариант; этот подход позволяет использовать элемент 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 );
      }

  }

}

Тема t = новая тема (новый MyRunnable (параметр));  t.start();

Если вам нужен результат обработки, вам также необходимо будет скоординировать завершение MyRunnable, когда закончится подзадание. Вы можете передать обратный вызов или просто подождать на тему "t" и т.д.

Ответ 15

Специально для 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();
}

Ответ 16

Нет, вы не можете передать параметры методу 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();

Как только вы это сделаете - вы должны быть осторожны с целостностью данных объекта, который вы передаете в "WorkingTask". Теперь данные будут существовать в двух разных потоках, поэтому вы должны убедиться, что это Thread Safe.

Ответ 17

Создайте локальную переменную в своем классе, которая 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"

Ответ 18

Я знаю, что опоздал на несколько лет, но я столкнулся с этой проблемой и принял неортодоксальный подход. Я хотел сделать это без создания нового класса, вот что я придумал:

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