wake-up-neo.com

Code im Haupt-Thread von einem Sekundär-Thread ausführen?

Dies ist eine allgemeine Java-Frage und keine erstmalige Android-Frage!

Ich möchte wissen, wie Code im Haupt-Thread aus dem Kontext eines Sekundär-Threads 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();

So etwas - ich weiß, dass mein Beispiel etwas armselig ist, da Sie in Java nicht im Haupt-Thread sein müssen, um etwas auszudrucken, und dass Swing auch eine Ereigniswarteschlange hat - aber die generische Situation, in der Sie dies möglicherweise tun müssen run sagt ein Runable im Haupt-Thread, während es sich im Hintergrund eines Hintergrund-Threads befindet.

EDIT: Zum Vergleich - so würde ich es in Objective-C machen:

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

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

Danke im Voraus!

26
Javawag

Es gibt keine universelle Möglichkeit, einfach Code an einen anderen laufenden Thread zu senden und "Hey, du, mach das" zu sagen. Sie müssten den Haupt-Thread in einen Zustand versetzen, in dem er über einen Mechanismus zum Empfangen von Arbeit verfügt und auf Arbeit wartet.

Hier ist ein einfaches Beispiel für das Einrichten des Haupt-Threads, um darauf zu warten, dass er die Arbeit von anderen Threads erhält und bei seiner Ankunft ausführt. Natürlich möchten Sie einen Weg hinzufügen, um das Programm tatsächlich 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();
    }
}
26
Affe

Falls Sie mit Android arbeiten, sollten Sie einen Handler verwenden?

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

Eine alte Diskussion, aber wenn es darum geht, eine Anfrage an den Haupt-Thread zu senden (eine nicht umgekehrte Richtung), können Sie dies auch mit Futures tun. 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 Sie mehrere Dinge im Hintergrund ausführen und die Ergebnisse abrufen möchten, können Sie wie oben erwähnt einige Warteschlangen festlegen oder den Prozess in mehrere Futures aufteilen (alle gleichzeitig starten oder bei Bedarf eine neue starten, sogar aus einer anderen Zukunft) . Wenn Sie jede Aufgabe in einer Karte oder Liste speichern, die im Haupt-Thread initialisiert wurde, können Sie jederzeit die gewünschten Futures überprüfen und deren Ergebnisse abrufen.

7
Matthieu

Möglicherweise möchten Sie den Thread "Even Dispatching" verwenden, an dem die meisten ereignisgesteuerten Ereignisse auftreten. Wenn Sie Swing verwenden, dann:

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

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

3
Mycenae

Wenn Sie JavaFX verwenden, was ich sehr empfehle, können Sie es verwenden

    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            alert(text);
        }
    });

von Ihrem Nicht-UI-Thread aus, und der Runable wird vom UI-Thread ausgeführt, wenn er von Ihrem Thread zurückgegeben wird.

0
Antinous