web-dev-qa-db-fra.com

Comment puis-je passer un paramètre à un thread Java?

Quelqu'un peut-il me suggérer comment je peux passer un paramètre à un thread?

Aussi, comment ça marche pour les classes anonymes?

253
Steve

Vous devez passer le paramètre du constructeur à l'objet Runnable:

public class MyRunnable implements Runnable {

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

   public void run() {
   }
}

et l'invoquez ainsi:

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

Pour les cours anonymes:

En réponse aux questions éditées, voici comment cela fonctionne pour les classes anonymes

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

Cours nommés:

Vous avez une classe qui étend Thread (ou implémente Runnable) et un constructeur avec les paramètres que vous souhaitez transmettre. Ensuite, lorsque vous créez le nouveau fil, vous devez passer les arguments, puis démarrez le fil, quelque chose comme ceci:

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

Runnable est une bien meilleure solution que Thread BTW. Donc je préférerais:

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

Cette réponse est fondamentalement la même que cette question similaire: Comment passer des paramètres à un objet Thread

101
Nick Fortescue

via le constructeur d'une classe Runnable ou 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();
}
37
dfa

Lorsque vous créez un thread, vous avez besoin d'une instance de Runnable. Le moyen le plus simple de passer un paramètre est de le transmettre en tant qu’argument au constructeur:

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

Si vous souhaitez ensuite modifier le paramètre pendant que le thread est en cours d'exécution, vous pouvez simplement ajouter une méthode de définition à votre classe exécutable:

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

Une fois que vous avez cela, vous pouvez changer la valeur du paramètre en appelant comme ceci:

myRunnable.setMyParam("Goodbye World");

Bien sûr, si vous souhaitez déclencher une action lorsque le paramètre est modifié, vous devrez utiliser des verrous, ce qui rend les choses beaucoup plus complexes.

16
jwoolard

Cette réponse arrive très tard, mais peut-être que quelqu'un le trouvera utile. Il s'agit de savoir comment passer un paramètre à une Runnable sans même déclarer la classe nommée (pratique pour les 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();

Bien sûr, vous pouvez reporter l’exécution de start à un moment plus pratique ou plus approprié. Et c'est à vous de décider quelle sera la signature de la méthode init (elle pourra donc prendre plus d'arguments et/ou différents) et bien sûr même son nom, mais vous avez une idée.

En fait, il existe également un autre moyen de passer un paramètre à une classe anonyme en utilisant les blocs d'initialisation. Considère ceci:

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

Donc tout se passe à l'intérieur du bloc d'initialisation.

15
Cromax

Pour créer un thread, vous créez normalement votre propre implémentation de Runnable. Passez les paramètres au thread dans le constructeur de cette classe.

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

Vous pouvez soit étendre le Threadclass ou le Runnableclass et fournir les paramètres souhaités. Il existe des exemples simples dans les docs . Je vais les porter ici:

 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
bruno conde

Soit vous écrivez une classe qui implémente Runnable et transmettez ce dont vous avez besoin dans un constructeur défini de manière appropriée, soit vous écrivez une classe qui étend Thread avec un constructeur correctement défini qui appelle super () avec les paramètres appropriés.

7
PaulJWilliams

A partir de Java 8, vous pouvez utiliser un lambda pour capturer des paramètres qui sont effectivement définitifs . Par exemple:

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
Jeff G

Vous pouvez dériver une classe de Runnable et, lors de la construction (par exemple), passez le paramètre dans.

Puis lancez-le en utilisant Thread.start (Runnable r);

Si vous voulez dire while le thread est en cours d'exécution, maintenez simplement une référence à votre objet dérivé dans le thread appelant et appelez les méthodes de définition appropriées (synchronisation le cas échéant)

3
Brian Agnew

Paramètre passant par les méthodes start () et 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);
}
3
Java42

Il existe un moyen simple de passer des paramètres à runnables . Code:

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

Dans Java 8, vous pouvez utiliser les expressions lambda avec l'API Concurrency & the ExecutorService comme remplacement de niveau supérieur pour l'utilisation directe de threads:

newCachedThreadPool() Crée un pool de threads qui crée de nouveaux threads au besoin, mais réutilisera les threads précédemment construits quand ils sont disponible. Ces pools amélioreront généralement les performances des programmes qui exécutent de nombreuses tâches asynchrones de courte durée.

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

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

Voir aussi executorsjavadocs .

2
Stuart Cardall

Spécialement pour Android

Pour rappel, j'implémente généralement ma propre Runnable générique avec le ou les paramètres d'entrée:

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

L'utilisation est simple:

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

En manager:

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
Andrei

Non, vous ne pouvez pas transmettre de paramètres à la méthode run(). La signature vous dit que (il n'a pas de paramètres). La méthode la plus simple consiste probablement à utiliser un objet spécialement conçu, qui prend un paramètre dans le constructeur et le stocke dans une variable finale: 

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

Une fois que vous avez fait cela, vous devez faire attention à l'intégrité des données de l'objet que vous passez dans la 'WorkingTask'. Les données vont maintenant exister dans deux threads différents, vous devez donc vous assurer qu'il s'agit de Thread Safe.

1
Mihir Patel

Une autre option; Cette approche vous permet d'utiliser l'élément Runnable comme un appel de fonction asynchrone. Si votre tâche n'a pas besoin de renvoyer un résultat, par exemple, il effectue simplement une action dont vous n'avez pas besoin de vous inquiéter pour savoir comment vous transmettez un "résultat".

Ce modèle vous permet de réutiliser un élément pour lequel vous avez besoin d’une sorte d’état interne. Lorsque vous ne passez pas de paramètre (s) dans le constructeur, vous devez prendre soin des programmes pour accéder aux paramètres. Vous aurez peut-être besoin de plus de vérifications si votre cas d'utilisation implique différents appelants, etc.

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

  }

}

Fil t = nouveau fil (nouveau MyRunnable (paramètre)); t.start ();

Si vous avez besoin d'un résultat de traitement, vous devrez également coordonner l'achèvement de MyRunnable à la fin de la sous-tâche. Vous pouvez renvoyer un appel ou simplement attendre le fil de discussion, etc.

1
will

Je sais que j'ai quelques années de retard, mais je suis tombé sur cette question et ai adopté une approche peu orthodoxe. Je voulais le faire sans créer de nouveau cours. Voici donc ce que je propose: 

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

Créez une variable locale dans votre classe qui extends Thread ou 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;
    }}

De cette façon, vous pouvez passer une variable lorsque vous l'exécutez.

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

Le résultat:

"www.google.com"
0
calthecoder