2011-01-11 14 views
2

Sagen Sie zum Beispiel, dass ich eine Runnable namens RunnableA, die etwas tut. Ich habe auch ein Runnable namens RunnableB, das etwas anderes tut. Gibt es eine Möglichkeit, diese beiden Runnables so zu kombinieren, dass sie im gleichen Thread laufen?Kombinieren von zwei runable Objekte

Der zweite Teil der Frage ist, wenn dies möglich ist, kann ich dann die Reihenfolge angeben, in der sie ausgeführt werden?

BEARBEITEN !: Der Grund, warum ich das tun wollte, war, weil ich Code auf dem EDT ausführen muss, aber ein Teil des anderen Codes muss auf einem anderen Thread ausgeführt werden. Bitte sehen Sie sich den folgenden Code an.

So etwas wie dieses

 

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

Sorry, wenn dies ist nicht gut erklärt, Kommentare zu schreiben, wenn Sie brauchen Klarheit.

Danke!

+0

Wenn Sie diese auf dem gleichen Thread in einer angegebenen Reihenfolge ausführen müssen, ist es nicht genau ein Multithread-Problem. Können Sie stattdessen Ihren Code aus den Runnables extrahieren? – Juliet

Antwort

8

Nun können Sie sicherlich ein Runnable schaffen, die runnable läuft nur eine dann die andere:

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

Allgemeiner gesagt, man könnte es eine Iterable<Runnable>, kopieren Sie alle Runnable Referenzen machen nehmen und sie dann laufen, um . Zum Beispiel:

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

Vielen Dank. Ich habe Ihren Code etwas modifiziert und im obigen Beispiel verwendet. Kannst du mich wissen lassen, was du denkst? – user489041

+0

@ user489041: Nun, Sie haben die Generika entfernt, um damit zu beginnen ... warum? –

+0

@ Jon Skeet Ich konnte die Funktion Lists.newArrayList (Runnables) nicht verwenden. Ist dies ein Teil von com.google.common.collect.Lists? – user489041

3

Sicher. Erstellen Sie einfach ein anderes Runnable, das die Run-Methoden Ihrer beiden vorhandenen Runnable als Teil seiner Implementierung aufruft. Sie können den Wickel Runnable Zweck gebaute oder generic mit einer Liste von Runnables machen usw.

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

    return retVal; 
} 

Vielleicht, was dir verwirrend ist Vereinigung von Runnable mit Gewinden. Die Runnable-Schnittstelle ist nicht an Threads gebunden und hat selbst keine Threading-Semantik, so dass Sie sie einfach kombinieren können, ohne mit Thread-Zuständen irgendwie in Schwierigkeiten zu geraten.

+0

Ja, ich denke, deshalb bin ich verwirrt. Ich denke, dass ich weit darüber denke.Ich war auf der Suche nach einer generellen Methode, mit der ich Code auf dem EDT starten und herunterfahren und dann einen Worker-Code in seinem eigenen Thread ausführen konnte. Deshalb habe ich mich gefragt, ob ich sie so kombinieren könnte. Mein Versuch basierend auf den Antworten wurde oben gepostet. – user489041

+0

Wahrscheinlich sollten Ausnahmen von der ersten abfangen und an den nicht abgefangenen Exception-Handler übergeben werden. Es ist bedauerlich, dass "Runnable" so wenig Bedeutung hat. –

2

Ja, Sie können sie natürlich kombinieren. Im Allgemeinen sollte jedoch außer einem Aufruf an ein anderes Objekt nicht viel in einem Runnable vorhanden sein, um die Arbeit tatsächlich zu erledigen. Können Sie nicht einfach die "Inside" der benötigten Runnables nehmen und sie in dem von Ihnen gewünschten Kontext ausführen?

Wenn Sie sicherstellen möchten, dass die Dinge einfach nacheinander und nicht gleichzeitig ausgeführt werden, können Sie einen SingleThreadExecutorService verwenden und ihnen die Runnables geben. Es wird jeweils einzeln ausgeführt.

Wenn Sie wirklich mehrere Runnables ausführen möchten, können Sie dies so tun (die erste RuntimeException wird beendet).

Beachten Sie die statische bequeme Methode, so dass Sie "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

Eine weitere Variante sagen kann.

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