Kann mir jemand vorschlagen, wie ich einen Parameter an einen Thread übergeben kann?
Wie funktioniert es auch für anonyme Klassen?
Consumer<T>.
Kann mir jemand vorschlagen, wie ich einen Parameter an einen Thread übergeben kann?
Wie funktioniert es auch für anonyme Klassen?
Consumer<T>.
Antworten:
Sie müssen den Parameter im Konstruktor an das Runnable-Objekt übergeben:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
und rufe es so auf:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
rdasselbe Argument hat. Wenn wir also unterschiedliche Argumente an mehrere ausgeführte Threads übergeben möchten, MyThreadmüssen wir eine neue MyThreadInstanz mit dem gewünschten Argument für jeden Thread erstellen . Mit anderen Worten, um einen Thread zum Laufen zu bringen, müssen zwei Objekte erstellt werden: Thread und MyThread. Wird dies in Bezug auf die Leistung als schlecht angesehen?
Als Antwort auf Fragenbearbeitungen erfahren Sie hier, wie es für anonyme Klassen funktioniert
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Sie haben eine Klasse, die Thread erweitert (oder Runnable implementiert), und einen Konstruktor mit den Parametern, die Sie übergeben möchten. Wenn Sie dann den neuen Thread erstellen, müssen Sie die Argumente übergeben und dann den Thread starten, ungefähr so:
Thread t = new MyThread(args...);
t.start();
Runnable ist eine viel bessere Lösung als Thread BTW. Also würde ich bevorzugen:
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();
Diese Antwort entspricht im Wesentlichen der ähnlichen Frage: Übergeben von Parametern an ein Thread-Objekt
parameterdirekt von der run()Methode aus zugreife , ohne ein Feld wie dieses pzu verwenden. Es scheint zu funktionieren. Gibt es ein subtiles Multithreading , was ich vermisse von nicht kopieren vorher? parameterp
)im ersten Beispiel
final X parametervor der new Runnable()Leitung hatte, konnte ich parameterhineingehen run(). Ich musste das Extra nicht tun p = parameter.
finalist nicht mehr so wichtig; Es ist genug, wenn die Variable effektiv endgültig ist (obwohl es keinen Schaden anrichtet)
über den Konstruktor einer Runnable- oder Thread-Klasse
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();
}
@Overridefür?
@Overrideexplizit an, dass die abstrakte Methode in der Thread-Klasse überschrieben wird.
Diese Antwort kommt sehr spät, aber vielleicht findet es jemand nützlich. Es geht darum, wie Sie einen oder mehrere Parameter an eine übergeben, Runnableohne eine benannte Klasse zu deklarieren (praktisch für Inliner):
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();
Natürlich können Sie die Ausführung startauf einen günstigeren oder angemesseneren Zeitpunkt verschieben. Und es liegt an Ihnen, was die Signatur der initMethode sein wird (es kann also mehr und / oder andere Argumente erfordern) und natürlich sogar ihren Namen, aber im Grunde haben Sie eine Idee.
Tatsächlich gibt es auch eine andere Möglichkeit, einen Parameter unter Verwendung der Initialisierungsblöcke an eine anonyme Klasse zu übergeben. Bedenken Sie:
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();
Alles geschieht also innerhalb des Initialisierungsblocks.
this.myParamdann wirklich notwendig? Könnten Sie nicht einfach die privaten Variablen löschen und auf die Variable aus dem äußeren Bereich verweisen? Ich verstehe (natürlich), dass dies einige Auswirkungen hat, z. B. dass die Variable nach dem Starten des Threads offen ist, um sich zu ändern.
Wenn Sie einen Thread erstellen, benötigen Sie eine Instanz von Runnable. Der einfachste Weg, einen Parameter zu übergeben, besteht darin, ihn als Argument an den Konstruktor zu übergeben:
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();
Wenn Sie den Parameter dann ändern möchten, während der Thread ausgeführt wird, können Sie Ihrer ausführbaren Klasse einfach eine Setter-Methode hinzufügen:
public void setMyParam(String value){
this.myParam = value;
}
Sobald Sie dies haben, können Sie den Wert des Parameters ändern, indem Sie wie folgt aufrufen:
myRunnable.setMyParam("Goodbye World");
Wenn Sie beim Ändern des Parameters eine Aktion auslösen möchten, müssen Sie natürlich Sperren verwenden, was die Dinge erheblich komplexer macht.
Um einen Thread zu erstellen, erstellen Sie normalerweise Ihre eigene Implementierung von Runnable. Übergeben Sie die Parameter an den Thread im Konstruktor dieser Klasse.
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);
}
}
Sie können entweder die oder die und erweitern und Parameter angeben, wie Sie möchten. Es gibt einfache Beispiele in den Dokumenten . Ich werde sie hier portieren: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();
Schreiben Sie entweder eine Klasse, die Runnable implementiert, und übergeben Sie alles, was Sie benötigen, in einem entsprechend definierten Konstruktor, oder schreiben Sie eine Klasse, die Thread um einen entsprechend definierten Konstruktor erweitert, der super () mit entsprechenden Parametern aufruft.
Ab Java 8 können Sie ein Lambda verwenden, um Parameter zu erfassen, die effektiv endgültig sind . Zum Beispiel:
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();
In Java 8 können Sie lambdaAusdrücke mit der Concurrency-API und dem ExecutorServiceals übergeordneten Ersatz für die direkte Arbeit mit Threads verwenden:
newCachedThreadPool()Erstellt einen Thread-Pool, der nach Bedarf neue Threads erstellt, zuvor erstellte Threads jedoch wiederverwendet, sobald sie verfügbar sind. Diese Pools verbessern normalerweise die Leistung von Programmen, die viele kurzlebige asynchrone Aufgaben ausführen.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Siehe auch executors Javadocs .
Ich weiß, dass ich ein paar Jahre zu spät bin, aber ich bin auf dieses Problem gestoßen und habe einen unorthodoxen Ansatz gewählt. Ich wollte es tun, ohne eine neue Klasse zu bilden, also habe ich mir Folgendes ausgedacht:
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();
Parameterübergabe über die Methoden start () und 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);
}
Sie können eine Klasse von Runnable ableiten und während der Konstruktion (z. B.) den Parameter übergeben.
Starten Sie es dann mit Thread.start (Runnable r).
Wenn Sie meinen, während der Thread ausgeführt wird, halten Sie einfach einen Verweis auf Ihr abgeleitetes Objekt im aufrufenden Thread und rufen Sie die entsprechenden Setter-Methoden auf (ggf. synchronisieren).
Nein, Sie können keine Parameter an die run()Methode übergeben. Die Signatur sagt Ihnen das (es hat keine Parameter). Der wahrscheinlich einfachste Weg, dies zu tun, wäre die Verwendung eines speziell erstellten Objekts, das einen Parameter im Konstruktor übernimmt und in einer endgültigen Variablen speichert:
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();
Sobald Sie dies getan haben, müssen Sie auf die Datenintegrität des Objekts achten, das Sie an die 'WorkingTask' übergeben. Die Daten sind jetzt in zwei verschiedenen Threads vorhanden, sodass Sie sicherstellen müssen, dass sie threadsicher sind.
Eine weitere Option; Mit diesem Ansatz können Sie das Element Runnable wie einen asynchronen Funktionsaufruf verwenden. Wenn Ihre Aufgabe kein Ergebnis zurückgeben muss, z. B. nur eine Aktion ausführt, müssen Sie sich keine Gedanken darüber machen, wie Sie ein "Ergebnis" zurückgeben.
Mit diesem Muster können Sie ein Element wiederverwenden, für das Sie einen internen Status benötigen. Wenn Parameter im Konstruktor nicht übergeben werden, ist Sorgfalt erforderlich, um den Programmzugriff auf Parameter zu vermitteln. Möglicherweise benötigen Sie weitere Überprüfungen, wenn Ihr Anwendungsfall verschiedene Anrufer usw. umfasst.
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 = neuer Thread (neuer MyRunnable (Parameter)); t.start ();
Wenn Sie ein Ergebnis der Verarbeitung benötigen, müssen Sie auch den Abschluss von MyRunnable koordinieren, wenn die Unteraufgabe abgeschlossen ist. Sie können einen Rückruf weiterleiten oder einfach auf den Thread 't' usw. warten.
Für Rückrufzwecke implementiere ich normalerweise mein eigenes Generikum Runnablemit Eingabeparametern:
public interface Runnable<TResult> {
void run(TResult result);
}
Die Verwendung ist einfach:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
Im 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();
}
Erstellen Sie eine lokale Variable in Ihrer Klasse, die extends Threadoder 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;
}}
Auf diese Weise können Sie eine Variable übergeben, wenn Sie sie ausführen.
Extractor e = new Extractor("www.google.com");
e.start();
Die Ausgabe:
"www.google.com"