2010-02-20 40 views
17

Mögliches Duplikat: need-help-returning-object-in-thread-run-methodZugriff auf ein ausführbares Objekt per Thread?

Hallo. Ich habe eine Klasse, die runnable implementiert und ich habe eine Liste, die Threads speichert, die mit verschiedenen Objekten dieser Klasse instanziiert sind. Wie kann ich auf Eigenschaften von zugrunde liegenden Objekten zugreifen, wenn das Thread-Objekt sie ausführt? Hier ein Beispiel:

public class SO { 
    public static class TestRunnable implements Runnable { 
     public String foo = "hello"; 

     public void run() { 
      foo = "world"; 
     } 
    } 

    public static void main(String[] args) { 
     Thread t = new Thread(new TestRunnable()); 
     t.start(); 
     //How can I get the value of `foo` here? 
    } 
} 
+1

Abgesehen von nicht wirklich sicher zu sein, was Sie im Kopf haben, ich glaube, Sie Reflexion für diese benötigen, und Stellen Sie außerdem sicher, dass kein Sicherheitsmanager auf Ihrem Weg ist. Vielleicht könnten Sie jedoch detaillierter beschreiben, was Sie erreichen möchten. –

+0

Ich glaube, Sie können 'Thread' selbst ableiten und' Thread.run() 'außer Kraft setzen, anstatt ein' Runnable' zu ​​übergeben. Dann wäre 'foo' nur ein Attribut des' Threads'. – MatrixFrog

+1

@MatrixFrog: Dies ist nicht gut, wenn die Runnable-Klasse etwas anderes unterklassifizieren muss, da Java nur eine einzige Vererbung zulässt. Der Hauptzweck von java.lang.Runnable, so weit ich das beurteilen kann, besteht darin, dieses Problem zu umgehen, indem Sie Thread (java.lang.Runnable) zum Hinzufügen von Thread-Funktionalität zu einer Klasse, die bereits etwas anderes subklassifiziert, verwenden können. –

Antwort

12

Ich habe keine Art und Weise sehen, es zu tun in dem java.lang.Thread docs.

Meine beste Antwort ist dann, dass Sie wahrscheinlich List<Runnable> statt (oder zusätzlich) List<Thread> verwenden sollten. Oder vielleicht möchten Sie eine Art map Struktur, so dass Sie auf das Runnable vom Thread zugreifen können. (Zum Beispiel java.util.HashMap<java.lang.Thread, java.lang.Runnable>)

+0

Sie können Code-Anführungszeichen verwenden, um einfach '<>' s zu verwenden und die 'Liste ' mit '' s – Tanzelax

+0

@Tanzelax zu füllen: Oh wow, das wusste ich auch. Warum ich nicht daran gedacht habe, meinen Code zu formatieren, weiß ich nicht. Alles was ich sagen kann ist, dass es ein wirklich langer Tag war. Danke für den Tipp. –

+0

Ich bin neugierig auf den Downvote. Wer hat es gemacht? –

4
TestRunnable r = new TestRunnable(); 
Thread t = new Thread(r); 
t.start(); 
//there you need to wait until thread is finished, or just a simple Thread.sleep(1000); at this case 
System.out.println(r.foo); 

BTW, im realen Fall, dass Sie Callable und FutureTask

+2

Also zusammenfassend, es gibt keine Möglichkeit es zu tun, oder? Sie müssen sowohl auf den Thread als auch auf das ausführbare Objekt verweisen. Ich wäre dankbar, wenn Sie Ihren Anspruch auf Callable und FutureTask belegen könnten. –

+0

Ja, Sie benötigen einen Verweis auf das Objekt, das Sie ausführen und das Ergebnis an Sie zurückgibt, ein 'Runnable 'in diesem Fall. 'Callable' und' FutureTask' sind geeignetere Methoden, um Dinge zu tun, die Sie wollen. –

+2

Ich denke, ich sehe es einfach nicht. –

1

Dies ist zu verwenden, wie Sie dies direkt umsetzen können.

public static void main(String[] args) { 
    // Keep a reference to the runnable object for later ... 
    TestRunnable r = new TestRunnable(); 
    Thread t = new Thread(r); 
    t.start(); 
    // Wait until the child thread has finished 
    t.join(); 
    // Pull the result out of the runnable. 
    System.out.println(r.foo); 
} 

jedoch der moderne (weniger fehleranfällig) Weg, um diese Art der Sache zu tun ist, die auf höhere Ebene Concurrency Klassen in java.util.concurrent zu verwenden.

4

Wenn Sie den Wert eines asynchronen Berechnung zurückkehren möchten, schauen Sie sich aufrufbare und FutureTask:

FutureTask<String> task = new FutureTask(new Callable<String>() { 
    public String call() { 
     return "world"; 
    } 
}); 
new Thread(task).start(); 
String result = task.get(); 
10

Die Gleichzeitigkeit Bibliothek dies auch unterstützt. Hinweis: Wenn Sie Ihre Aufgabe eine Ausnahme auslöst, wird die Zukunft dieses halten und eine Verpackungs Ausnahme auslösen, wenn Sie anrufen get()

ExecutorService executor = Executors.newSingleThreadedExecutor(); 

Future<String> future = executor.submit(new Callable<String>() { 
    public String call() { 
     return "world"; 
    } 
}); 

String result = future.get(); 
+2

Wahrscheinlich möchten Sie den Executor danach herunterfahren. – Thilo

2

ich im Allgemeinen denken, Sie können/sollten dies vermeiden zu tun, aber wenn Sie wirklich brauchen sollte es nicht so etwas wie MatrixFrogs Vorschlag funktionieren (ungetestet):

class RunnableReferencingThread extends Thread { 
    public final Runnable runnable; 
    public RunnableReferencingThread(Runnable r) { 
     this.runnable = r; 
     super(r); 
    } 
} 

?

+0

Das wird nicht wie geschrieben kompilieren. – gerardw

+0

@gerardw: Ich habe gerade eine Bearbeitung eingereicht, die das korrigieren sollte (die beiden Anweisungen des Konstruktors werden so ausgetauscht, dass der Superaufruf die erste Anweisung des Konstruktors ist). –

0

Sie könnten Thread ableiten und die von Ihnen benötigte Methode hinzufügen. Sie müssen Ihre eigene Kopie des Ziels "Runnable" behalten und alle Thread-Konstruktoren, die Sie zum Erstellen des Threads verwenden, überschreiben, da einige Implementierungsdetails von Thread lästig sind.

1

Ich hatte das gleiche Problem. Hier ist meine Lösung:

public static class TestRunnable implements Runnable { 
    public String foo = "hello"; 

    public void run() { 
     foo = "world"; 
    } 

public static void main(String[] args) { 
    TestRunnable runobject = new TestRunnable(); 
    Thread t = new Thread(runobject); 
    runobject.foo; //The variable from runnable. hello; 
    t.start(); 
    runobject.foo; //The variable from runnable. world; 
} 
1

Wenn Ihr Thread-Zustandsinformationen hat, vergessen Runnable und einfach Thema erweitern, das Überschreiben der run-Methode.

1

Um ein konkretes Beispiel von Paul Crowley Lösung zu geben, ich denke, das ist, was er verspricht:

public class BackgroundJob<JOB extends Runnable> extends Thread { 

    private final JOB mJob; 

    public BackgroundJob(JOB job) { 
     super(job); 
     mJob = job; 
    } 

    public JOB getJob() { 
     return mJob; 
    } 

} 
Verwandte Themen