web-dev-qa-db-fra.com

Comment accéder à un objet Runnable par Thread?

Double possible: besoin-aide-retour-objet-dans-thread-méthode-exécution

Bonjour. J'ai une classe implémentant runnable et une liste 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 étant donné que l'objet thread 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?
    }
}
20
Fluffy

Je ne vois aucun moyen de le faire dans 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 voulez-vous une sorte de map structure pour pouvoir accéder à Runnable à partir du thread. (Par exemple, Java.util.HashMap<Java.lang.Thread, Java.lang.Runnable>)

12
Platinum Azure

La bibliothèque d'accès simultané le supporte bien. Remarque: Si votre tâche génère une exception, l’avenir la conservera et lancera 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(); 
10
Peter Lawrey

Si vous souhaitez renvoyer la valeur d'un calcul asynchrone, consultez Callable et FutureTask:

FutureTask<String> task = new FutureTask(new Callable<String>() {
   public String call() {
      return "world";
   }
});
new Thread(task).start();
String result = task.get();
4
Thilo
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, dans le cas réel, vous devez utiliser Callable et FutureTask

4
Igor Artamonov

Je pense qu'en général, vous pouvez/devriez éviter de faire cela, mais si vous avez vraiment besoin de le faire, ne faites pas quelque chose qui ressemble au travail de suggestion de MatrixFrog (non testé):

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

?

2
Chinasaur

Si votre thread contient des informations d'état, oubliez Runnable et développez simplement Thread en remplaçant la méthode d'exécution.

2
gerardw

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
user1870213

Voici comment vous pouvez implémenter ceci 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, la manière moderne (moins sujette aux erreurs) de faire ce genre de choses consiste à utiliser les classes de simultanéité de niveau supérieur dans Java.util.concurrent.

1
Stephen C

Pour donner un exemple concret de la solution de Paul Crowley, je pense que voici 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;
    }

}
1
Janus Varmarken

Je pense que si vous le pouvez, c'est pour inverser la situation. Dans ce cas, une bonne solution consiste à stocker le fil dans votre classe exécutable. Et votre exécutable a une fonction start () qui se lance et se lance elle-même le thread local et appelle thread.start. Comme cela, vous pouvez avoir une liste de vos objets threadés. Aussi, vous pouvez avoir un accesseur pour obtenir le fil.

public class Threaded extends other implements Runnable {
    Thread localThread;

    @Override
    public void run() {
        //...
    }

    public void start() {
        localThread = new Thread(this);
        localThread.start();
    }

}
0
user9717730

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

0
Paul Crowley