Java 从辅助线程在主线程上运行代码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16268693/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:05:38  来源:igfitidea点击:

Running code on the main thread from a secondary thread?

javamultithreadingconcurrencysynchronization

提问by Javawag

This is a general Java question and not an Android one first off!

这是一个通用的 Java 问题,而不是 Android 问题!

I'd like to know how to run code on the main thread, from the context of a secondary thread. For example:

我想知道如何从辅助线程的上下文中在主线程上运行代码。例如:

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

That sort of thing - I realise my example is a little poor since in Java you don't need to be in the main thread to print something out, and that Swing has an event queue also - but the generic situation where you might need to run say a Runnable on the main thread while in the context of a background thread.

那种事情 - 我意识到我的例子有点糟糕,因为在 Java 中你不需要在主线程中打印一些东西,而且 Swing 也有一个事件队列 - 但是你可能需要的一般情况在后台线程的上下文中,在主线程上运行说一个 Runnable 。

EDIT: For comparison - here's how I'd do it in Objective-C:

编辑:为了比较 - 这是我在 Objective-C 中的做法:

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

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

Thanks in advance!

提前致谢!

采纳答案by Affe

There is no universal way to just send some code to another running thread and say "Hey, you, do this." You would need to put the main thread into a state where it has a mechanism for receiving work and is waiting for work to do.

没有通用的方法可以将一些代码发送到另一个正在运行的线程并说“嘿,你,做这个。” 您需要将主线程置于具有接收工作机制并等待工作完成的状态。

Here's a simple example of setting up the main thread to wait to receive work from other threads and run it as it arrives. Obviously you would want to add a way to actually end the program and so forth...!

这是一个简单的示例,它设置主线程以等待从其他线程接收工作并在它到达时运行它。显然,您想添加一种方法来实际结束程序等等......!

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

回答by HarryS

In case you are on Android, using a Handler should do the job?

如果您使用的是 Android,使用 Handler 应该可以完成这项工作吗?

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

回答by Matthieu

An old discussion, but if it is a matter of sending request to the main thread (an not the opposite direction) you can also do it with futures. The basic aim is to execute something in background and, when it is finished, to get the result:

一个古老的讨论,但如果是向主线程发送请求(不是相反的方向),你也可以用期货来做。基本目标是在后台执行某些操作,并在完成后获得结果:

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.
}

If your intention is to do several stuff in background and retrieve the results, you can set some queues as said above or you can split the process in several futures (starting all at once or starting a new one when needed, even from another future). If you store each task in a map or a list, initialized in the main thread, you can check the futures that you want at anytime and get their results when they are done.

如果您的意图是在后台执行多项操作并检索结果,您可以设置一些队列,如上所述,或者您可以将过程拆分为多个未来(一次开始或在需要时开始一个新的,甚至从另一个未来开始) . 如果您将每个任务存储在地图或列表中,并在主线程中初始化,您可以随时查看您想要的期货,并在完成后获得它们的结果。

回答by Mycenae

You may want to use the 'even dispatching thread' where most event driven things happen. If you are using swing then:

您可能希望在大多数事件驱动的事情发生的地方使用“均匀调度线程”。如果您使用的是swing,那么:

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

Or create a class that implements Runnable and pass it into invokeLater().

或者创建一个实现 Runnable 的类并将其传递给 invokeLater()。

回答by Pixel

If you're using JavaFX, which I highly recommend, then you can use

如果您使用的是我强烈推荐的 JavaFX,那么您可以使用

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

from within your non-UI thread, and the runnable will executed from the UI thread on return from your thread.

从您的非 UI 线程中,并且 runnable 将从您的线程返回时从 UI 线程执行。