2011-01-11 4 views
2

Dites par exemple que j'ai un Runnable appelé RunnableA qui fait quelque chose. J'ai aussi un Runnable appelé RunnableB qui fait autre chose. Existe-t-il un moyen de combiner ces deux Runnables afin qu'ils tournent dans le même thread?Combinaison de deux objets Runnable

La deuxième partie de la question est de savoir si cela est possible, puis-je spécifier l'ordre dans lequel ils vont s'exécuter?

EDIT !: La raison pour laquelle je voulais faire ceci était parce que j'ai besoin d'exécuter du code sur l'EDT mais une partie de l'autre code doit être exécuté sur un autre thread. S'il vous plaît jeter un oeil sur le code ci-dessous.

Quelque chose comme ça

 

public final class CompoundRunnable implements Runnable 
{ 
    private final Iterable runnables; 

    public CompoundRunnable(Iterable runnables) 
    { 
     // From Guava. Easy enough to do by hand if necessary 
     this.runnables = Lists.newArrayList(runnables); 

    } 

    public CompoundRunnable(Runnable... runnables) 
    { 
     this(Arrays.asList(runnables)); 
    } 

    @Override 
    public void run() 
    { 
     for (Runnable runnable : runnables) 
     { 
      runnable.run(); 
     } 
    } 
} 
 
 

public void setStatusAndProgress(final String status,Runnable runnable) 
    { 
     Runnable startUpRunner = new Runnable() 
     { 
      public void run() 
      { 
       SwingUtilities.invokeLater(new Runnable() 
       { 
        public void run() 
        { 
         setStatus(status); 
         selfReference.getProgressBar().setIndeterminate(true); 
        } 

       }); 
      } 
     }; 
     Runnable cleanUpRunner = new Runnable() 
     { 
      public void run() 
      { 
       SwingUtilities.invokeLater(new Runnable() 
       { 
        public void run() 
        { 
         setStatus(""); 
         getProgressBar().setIndeterminate(false); 
        } 
       }); 
      } 
     }; 

     Runnable theRunner = new CompoundRunnable(startUpRunner,runnable,cleanUpRunner); 
     new Thread(theRunner).start(); 
    } 
 

Désolé si ce isnt bien expliqué, poster des commentaires si vous avez besoin des éclaircissements.

Merci!

+0

Si vous avez besoin que ces unités s'exécutent sur le même thread, dans un ordre spécifié, ce n'est pas exactement un problème multithread. Pouvez-vous extraire votre code des runnables à la place? – Juliet

Répondre

8

Eh bien, vous pouvez certainement créer un Runnable qui court juste un runnable puis l'autre:

public final class CompoundRunnable implements Runnable 
{ 
    private final Runnable first; 
    private final Runnable second; 

    public CompoundRunnable(Runnable first, Runnable second) 
    { 
     this.first = first; 
     this.second = second; 
    } 

    @Override 
    public void run() 
    { 
     first.run(); 
     second.run(); 
    } 
} 

Plus généralement, vous pouvez le faire prendre un Iterable<Runnable>, copiez tous les Runnable références, puis les exécuter dans l'ordre . Par exemple:

public final class CompoundRunnable implements Runnable 
{ 
    private final Iterable<Runnable> runnables; 

    public CompoundRunnable(Iterable<Runnable> runnables) 
    { 
     // From Guava. Easy enough to do by hand if necessary 
     this.runnables = Lists.newArrayList(runnables); 
    } 

    public CompoundRunnable(Runnable... runnables) 
    { 
     this(Arrays.asList(runnables)); 
    } 

    @Override 
    public void run() 
    { 
     for (Runnable runnable : runnables) 
     { 
      runnable.run(); 
     } 
    } 
} 
+0

Merci beaucoup. J'ai modifié un peu votre code et l'ai utilisé dans l'exemple ci-dessus. Pouvez-vous me dire ce que vous en pensez? – user489041

+0

@ user489041: Eh bien, vous avez supprimé les génériques pour commencer ... pourquoi? –

+0

@Jon Skeet Je ne pouvais pas utiliser la fonction Lists.newArrayList (runnables). Est-ce que cela fait partie de com.google.common.collect.Lists? – user489041

3

Bien sûr. Créez simplement un autre exécutable qui appelle les méthodes d'exécution de vos deux Runnable existants dans le cadre de son implémentation. Vous pouvez faire l'emballage Runnable construits ou générique avec une liste de runnables, etc.

public Runnable combineRunnables(Runnable a, Runnable b) 
{ 
    Runnable retVal = new Runnable() 
    { 
     public void run() 
     { 
      a.run(); 
      b.run(); 
     } 
    }; 

    return retVal; 
} 

Peut-être ce qui vous est source de confusion association de Runnable avec des fils. L'interface Runnable n'est pas liée aux threads et ne possède pas de sémantique de threading, vous pouvez donc facilement la combiner comme ci-dessus sans avoir de problèmes avec les états des threads.

+0

Oui, je pense que c'est pourquoi je suis confus. Je pense que je suis très en train de le penser.Je cherchais un moyen général de démarrer et d'arrêter le code sur l'EDT, puis d'exécuter du code de travail dans son propre thread. C'est pourquoi je me demandais si je pouvais les combiner d'une telle manière. Ma tentative basée sur les réponses a été posté ci-dessus. – user489041

+0

Probablement devrait attraper des exceptions du premier et le passer au gestionnaire d'exception uncaught. Il est regrettable que 'Runnable' ait si peu de sens. –

2

Oui, vous pouvez bien sûr les combiner. En général, cependant, il ne devrait pas y avoir beaucoup à l'intérieur d'un runnable, sauf un appel à un autre objet, pour réellement faire le travail. Ne pouvez-vous pas simplement prendre «l'intérieur» des runnables dont vous avez besoin et les exécuter dans le contexte que vous voulez.

Si vous voulez vous assurer que les choses sont simplement exécutées les unes après les autres, vous pouvez utiliser SingleThreadExecutorService et leur donner les Runnables. Il va s'exécuter un à la fois.

Si vous voulez vraiment exécuter plusieurs runnables, alors vous pouvez le faire comme ceci (la première RuntimeException va quitter).

Notez la méthode pratique statique de sorte que vous pouvez dire "new Thread (CompositeRunnable.combine (a, b, c, d ....))"

public class CompositeRunnable implements Runnable { 

    private final Runnable[] runnables; 

    public CompositeRunnable(Runnable... runnables) { 
     this.runnables = runnables; 
    } 

    public void run() { 
     for (Runnable runnable : runnables) { 
      runnable.run(); 
     } 
    } 

    public static Runnable combine(Runnable... runnables) { 
     return new CompositeRunnable(runnables); 
    } 
} 
1

Une autre variante.

public static Runnable combineRunnables(final Runnable... runnables) { 
    return new Runnable() { 
     public void run() { 
      for(Runnable r: runnables) r.run(); 
     } 
    }; 
}