2013-04-28 7 views
22

Dies ist eine allgemeine Java-Frage und nicht eine erste Android-Frage!Ausführen von Code auf dem Hauptthread von einem sekundären Thread?

Ich möchte wissen, wie Code aus dem Kontext eines sekundären Threads auf dem Hauptthread ausgeführt wird. Zum Beispiel:

new Thread(new Runnable() { 
     public void run() { 
      //work out pi to 1,000 DP (takes a while!) 

      //print the result on the main thread 
     } 
    }).start(); 

Dergleichen - Ich weiß, mein Beispiel ein wenig schlecht ist, da in Java Sie etwas aus zu drucken, nicht im Hauptthread sein müssen, und dass Schaukel hat auch eine Ereigniswarteschlange - aber die generische Situation, in der Sie möglicherweise laufen müssen, sagt im Kontext eines Hintergrundthreads eine ausführbare Anweisung für den Hauptthread.

EDIT: Zum Vergleich - hier ist, wie ich es in Objective-C tun würde:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{ 
    //do background thread stuff 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     //update UI 
    }); 
}); 

Vielen Dank im Voraus!

Antwort

25

Es gibt keine universelle Möglichkeit, nur einen Code an einen anderen laufenden Thread zu senden und zu sagen: "Hey, du, tu das." Sie müssten den Haupt-Thread in einen Zustand versetzen, in dem er einen Mechanismus zum Empfangen von Arbeit hat und auf Arbeit warten muss.

Hier ist ein einfaches Beispiel für das Einrichten des Haupt-Threads, um darauf zu warten, Arbeit von anderen Threads zu erhalten und es auszuführen, wie es ankommt. Natürlich möchten Sie einen Weg hinzufügen, um das Programm zu beenden und so weiter ...!

public static final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); 

public static void main(String[] args) throws Exception { 
    new Thread(new Runnable(){ 
     @Override 
     public void run() { 
      final int result; 
      result = 2+3; 
      queue.add(new Runnable(){ 
       @Override 
       public void run() { 
        System.out.println(result); 
       } 
      }); 
     } 
    }).start(); 

    while(true) { 
     queue.take().run(); 
    } 
} 
+0

Ah okay, also in der Praxis denke ich, dass diese Art den Zweck der Verwendung eines Hintergrundthreads vereitelt, da der Hauptthread blockiert ist und auf den Hintergrundthread wartet. Trotzdem sieht es wie ein ziemlich ordentlicher Mechanismus aus! Ich werde jetzt mehr über Warteschlangen lesen! – Javawag

+0

Sie könnten sicherlich den Haupt-Thread einige andere Arbeit tun und nur in der Warteschlange in Abständen überprüfen, anstatt nichts zu tun, sondern darauf zu blockieren. Aber irgendwann hört es auf, Dinge zu Hause zu brauen. Swing bietet vollkommen gute Werkzeuge für :) – Affe

+0

Eigentlich ist das eine ziemlich gute Idee für das, was ich tue - ich benutze Swing nicht, da das Projekt eigentlich ein einfaches Spiel ist mit der Slick2d-Engine (sonst hast du recht; ich würde einfach Swing's eingebaute Tools dafür verwenden!) – Javawag

17

Falls Sie mit Android arbeiten, sollte die Verwendung eines Handlers die Aufgabe erfüllen?

new Handler(Looper.getMainLooper()).post(new Runnable() { 
    @Override 
    public void run() { 
     ... 
    } 
}); 
+0

Ich weiß, dass es eine Methode namens 'runOnUIThread()' gibt, aber nicht in jedem Fall ist der Code in 'Activity' geschrieben. Diese Antwort hat mir viel Zeit gespart. Vielen Dank! – ManuQiao

+0

das Q ist nicht über Android, es hat nicht einmal den Android Tag. –

6

Eine alte Diskussion, aber wenn es darum geht, Anforderung an den Hauptthread des Sendens (eine nicht die entgegengesetzte Richtung), die Sie auch mit Futures tun können. Das grundlegende Ziel ist etwas im Hintergrund auszuführen und, wenn es fertig ist, das Ergebnis zu erhalten:

public static void main(String[] args) throws InterruptedException, ExecutionException { 
    // create the task to execute 
    System.out.println("Main: Run thread"); 
    FutureTask<Integer> task = new FutureTask<Integer>(
      new Callable<Integer>() { 

       @Override 
       public Integer call() throws Exception { 
        // indicate the beginning of the thread 
        System.out.println("Thread: Start"); 

        // decide a timeout between 1 and 5s 
        int timeout = 1000 + new Random().nextInt(4000); 

        // wait the timeout 
        Thread.sleep(timeout); 

        // indicate the end of the thread 
        System.out.println("Thread: Stop after " + timeout + "ms"); 

        // return the result of the background execution 
        return timeout; 
       } 
      }); 
    new Thread(task).start(); 
    // here the thread is running in background 

    // during this time we do something else 
    System.out.println("Main: Start to work on other things..."); 
    Thread.sleep(2000); 
    System.out.println("Main: I have done plenty of stuff, but now I need the result of my function!"); 

    // wait for the thread to finish if necessary and retrieve the result. 
    Integer result = task.get(); 

    // now we can go ahead and use the result 
    System.out.println("Main: Thread has returned " + result); 
    // you can also check task.isDone() before to call task.get() to know 
    // if it is finished and do somethings else if it is not the case. 
} 

Wenn Ihre Absicht ist, mehrere Sachen im Hintergrund und die Ergebnisse abrufen zu tun, können Sie einige Warteschlangen eingestellt, wie gesagt oben oder Sie können den Prozess in mehrere Futures aufteilen (starten alle auf einmal oder starten ein neues bei Bedarf, auch aus einer anderen Zukunft). Wenn Sie jede Aufgabe in einer Map oder einer Liste speichern, die im Hauptthread initialisiert wurde, können Sie die gewünschten Futures jederzeit überprüfen und ihre Ergebnisse erhalten, wenn sie fertig sind.

2

Sie können den 'even dispatching thread' verwenden, wo die meisten ereignisgesteuerten Dinge passieren. Wenn Sie mit Swing dann:

SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      Your code here. 
     } 
    }); 

Oder eine Klasse erstellen, die Runnable implementiert und übergeben sie in invokeLater().

Verwandte Themen