Quelqu'un peut-il me suggérer comment passer un paramètre à un fil?
En outre, comment cela fonctionne-t-il pour les classes anonymes?
Consumer<T>
.
Quelqu'un peut-il me suggérer comment passer un paramètre à un fil?
En outre, comment cela fonctionne-t-il pour les classes anonymes?
Consumer<T>
.
Réponses:
Vous devez passer le paramètre dans le constructeur à l'objet Runnable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
et l'invoquer ainsi:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
aura le même argument, donc si nous voulons passer différents arguments à plusieurs threads en cours d'exécution, MyThread
nous devons créer une nouvelle MyThread
instance en utilisant l'argument souhaité pour chaque thread. En d'autres termes, pour obtenir un thread opérationnel, nous devons créer deux objets: Thread et MyThread. Est-ce considéré comme mauvais sur le plan des performances?
En réponse aux modifications apportées aux questions, 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();
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 thread, vous devez passer les arguments, puis démarrer le thread, quelque chose comme ceci:
Thread t = new MyThread(args...);
t.start();
Runnable est une bien meilleure solution que Thread BTW. Je préfère donc:
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
parameter
directement à partir de la run()
méthode sans utiliser un champ comme p
du tout. Cela semble fonctionner. Y a-t-il quelque chose de multithread subtil qui me manque en ne copiant pas parameter
à l' p
avance?
)
dans le premier exemple
final X parameter
la new Runnable()
ligne avant , je pouvais accéder à l' parameter
intérieur run()
. Je n'avais pas besoin de faire le supplément p = parameter
.
final
n'est plus si important; c'est suffisant si la variable est effectivement finale (malgré cela ne fait pas de mal de l'avoir)
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();
}
@Override
pour?
@Override
déclare explicitement qu'il remplace la méthode abstraite dans la classe Thread.
Cette réponse arrive très tard, mais peut-être que quelqu'un la trouvera utile. Il s'agit de savoir comment passer un ou plusieurs paramètres à une Runnable
sans même déclarer de 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 start
à un moment plus pratique ou approprié. Et c'est à vous de décider quelle sera la signature de la init
méthode (donc cela peut prendre plus et / ou différents arguments) et bien sûr même son nom, mais en gros vous avez une idée.
En fait, il existe également une autre façon de passer un paramètre à une classe anonyme, avec l'utilisation des 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();
Tout se passe donc à l'intérieur du bloc d'initialisation.
this.myParam
alors vraiment nécessaire? Ne pourriez-vous pas simplement supprimer les variables privées et vous référer à la variable de la portée externe? Je comprends (bien sûr) que cela a des implications, telles que la variable pouvant être modifiée après le démarrage du thread.
Lorsque vous créez un thread, vous avez besoin d'une instance de Runnable
. Le moyen le plus simple de passer un paramètre serait de le passer en 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 l'exécution du thread, 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 ceci, 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 considérablement plus complexes.
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);
}
}
Vous pouvez étendre le ou le et fournir les paramètres que vous souhaitez. Il y a des exemples simples dans les documents . Je vais les porter ici:Thread
class
Runnable
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();
Soit écrivez une classe qui implémente Runnable et passez tout ce dont vous avez besoin dans un constructeur correctement défini, soit écrivez une classe qui étend Thread avec un constructeur correctement défini qui appelle super () avec les paramètres appropriés.
Depuis 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();
Dans Java 8, vous pouvez utiliser des lambda
expressions avec l' API de concurrence et le ExecutorService
comme remplacement de niveau supérieur pour travailler directement avec les threads:
newCachedThreadPool()
Crée un pool de threads qui crée de nouveaux threads selon les besoins, mais réutilisera les threads précédemment construits lorsqu'ils seront disponibles. Ces pools améliorent 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 executors
javadocs .
Je sais que j'ai quelques années de retard, mais je suis tombé sur ce problème et j'ai adopté une approche peu orthodoxe. Je voulais le faire sans faire de nouveau cours, c'est donc ce que j'ai trouvé:
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();
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);
}
Vous pouvez dériver une classe de Runnable, et pendant la construction (par exemple) passer le paramètre.
Ensuite, lancez-le en utilisant Thread.start (Runnable r);
Si vous voulez dire pendant que 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)
Non, vous ne pouvez pas transmettre de paramètres à la run()
méthode. La signature vous l'indique (elle n'a pas de paramètres). La façon la plus simple de le faire serait probablement d'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 existeront désormais dans deux threads différents, vous devez donc vous assurer qu'elles sont Thread Safe.
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, elle exécute simplement une action, vous n'avez pas à vous soucier de la façon dont vous transmettez un "résultat".
Ce modèle vous permet de réutiliser un élément, où vous avez besoin d'une sorte d'état interne. Lorsqu'il ne transmet pas de paramètre (s) dans le constructeur, une attention particulière est nécessaire pour assurer l'accès des programmes aux paramètres. Vous devrez peut-être 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 );
}
}
}
Thread t = nouveau Thread (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 Thread 't', etc.
À des fins de rappel, j'implémente généralement mon propre générique Runnable
avec des 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();
}
Créez une variable locale dans votre classe 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"