2010-02-20 1 views
17

Copie possible: need-help-returning-object-in-thread-run-methodComment accéder à un objet Runnable par Thread?

Bonjour. J'ai une classe implémentant runnable et j'ai un List, stockant des Threads instanciés avec différents objets de cette classe. Comment puis-je accéder aux propriétés des objets sous-jacents compte tenu de l'objet thread qui les exécute? Voici un exemple:

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

En plus de ne pas être vraiment sûr de ce que vous avez à l'esprit, je pense que vous aurez besoin de réflexion pour cela, et Assurez-vous également qu'il n'y a pas de gestionnaire de sécurité sur votre chemin. Toutefois, vous pourriez peut-être décrire plus en détail ce que vous essayez d'accomplir. –

+0

Je crois que vous pouvez sous-classer 'Thread' lui-même et remplacer' Thread.run() 'au lieu de lui passer un' Runnable'. Alors 'foo' serait juste un attribut du' Thread'. – MatrixFrog

+1

@MatrixFrog: Ce n'est pas bon si la classe Runnable a besoin de sous-classer quelque chose d'autre, puisque Java n'autorise qu'un seul héritage. Le but principal de java.lang.Runnable, pour autant que je sache, est de contourner ce problème en vous permettant d'utiliser Thread (java.lang.Runnable) pour ajouter une fonctionnalité de thread à une classe qui sous-classe déjà quelque chose d'autre. –

Répondre

12

Je ne vois aucune façon de le faire dans les java.lang.Thread docs. Ma meilleure réponse, alors, est que vous devriez probablement utiliser List<Runnable> au lieu de (ou en plus de) List<Thread>. Ou peut-être vous voulez une sorte de structure map afin que vous puissiez accéder à la Runnable à partir du Thread. (Par exemple, java.util.HashMap<java.lang.Thread, java.lang.Runnable>)

+0

Vous pouvez utiliser des citations de code pour utiliser directement '<>' s, en enveloppant la 'Liste ' avec 's – Tanzelax

+0

@Tanzelax: Oh wow, je le savais aussi. Pourquoi je n'ai pas pensé à l'utiliser pour mettre en forme mon code, je ne sais pas. Tout ce que je peux dire, c'est que la journée a été vraiment longue. Merci pour le conseil. –

+0

Je suis curieux de connaître le downvote. Celui qui l'a fait, a besoin d'expliquer? –

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, en cas réel, vous devez utiliser Callable et FutureTask

+2

Donc, en résumé, il n'y a aucun moyen de le faire, non? Vous devez conserver une référence à la fois au thread et au runnable. Je vous serais reconnaissant si vous pouviez justifier votre réclamation à propos de Callable et FutureTask. –

+0

Oui, vous avez besoin d'une référence à l'objet que vous exécutez et qui vous renvoie le résultat, un Runnable dans ce cas. 'Callable' et' FutureTask' est une façon plus appropriée de faire les choses que vous voulez. –

+2

Je suppose que je ne le vois tout simplement pas. –

1

Voici comment vous pouvez mettre en œuvre ce directement.

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

Cependant, le moderne (moins sujette aux erreurs) façon de faire ce genre de chose est d'utiliser les classes de concurrence plus haut niveau dans java.util.concurrent.

4

Si vous voulez retourner la valeur d'un calcul asynchrone, regardez appelable et FutureTask:

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

La bibliothèque prend en charge ce bien concurrency. Remarque: Si votre tâche renvoie une exception, l'avenir tiendra cela et jeter une exception d'emballage lorsque vous appelez get()

ExecutorService executor = Executors.newSingleThreadedExecutor(); 

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

String result = future.get(); 
+2

Vous souhaitez probablement arrêter l'exécuteur ultérieurement. – Thilo

2

Je pense qu'en général, vous pouvez/devrait éviter de le faire, mais si vous avez vraiment besoin ne devrait-il pas quelque chose comme la suggestion de MatrixFrog travail (non testé):

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

?

+0

Cela ne sera pas compilé comme écrit. – gerardw

+0

@gerardw: Je viens de soumettre une modification qui devrait corriger ceci (permuter les deux instructions du constructeur de telle sorte que le super appel soit la première instruction du constructeur) –

0

Vous pouvez sous-classer Thread et ajouter la méthode dont vous avez besoin. Vous devrez conserver votre propre copie de la Runnable cible et remplacer tous les constructeurs de Thread que vous utilisez pour créer le Thread, à cause des détails d'implémentation ennuyeux de Thread.

1

J'ai eu le même problème. Voici ma solution:

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

Si votre fil contient des informations d'état, oublier Runnable et simplement étendre cette discussion, redéfinissant la méthode d'exécution.

1

Pour donner un exemple concret de la solution de Paul Crowley, je pense que c'est ce qu'il suggère:

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

}