web-dev-qa-db-ja.com

セカンダリスレッドからメインスレッドでコードを実行していますか?

これは一般的なJavaの質問であり、Android 1回目ではありません!

セカンダリスレッドのコンテキストから、メインスレッドでコードを実行する方法を知りたいです。例えば:

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

そのようなこと-私は私の例が少し貧弱であることに気づきました:Javaしかし、バックグラウンドスレッドのコンテキスト内でメインスレッドでRunnableを実行する必要がある一般的な状況。

編集:比較のために、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
    });
});

前もって感謝します!

26
Javawag

実行中の別のスレッドにコードを送信して、「ちょっと、これをやる」と言う普遍的な方法はありません。メインスレッドを、作業を受け取るためのメカニズムがあり、作業の実行を待機している状態にする必要があります。

メインスレッドをセットアップして、他のスレッドからの作業を受信し、到着したときに実行するように設定する簡単な例を次に示します。明らかに、プログラムを実際に終了する方法などを追加したいでしょう...!

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

Androidを使用している場合、ハンドラーを使用して作業を行う必要がありますか?

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

古い議論ですが、メインスレッドに要求を送信することである場合(反対方向ではない場合)、futureでそれを行うこともできます。基本的な目的は、バックグラウンドで何かを実行し、終了したら結果を取得することです。

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

バックグラウンドでいくつかのことを行い、結果を取得することを目的とする場合は、上記のようにいくつかのキューを設定するか、いくつかの将来にプロセスを分割することができます。メインスレッドで初期化されたマップまたはリストに各タスクを保存すると、いつでも必要な先物を確認し、完了時に結果を取得できます。

7
Matthieu

ほとんどのイベント駆動型のことが起こる「偶数ディスパッチスレッド」を使用することができます。 swingを使用している場合:

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

または、Runnableを実装するクラスを作成し、invokeLater()に渡します。

3
Mycenae

JavaFXを使用している場合は、これを強くお勧めします。

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

非UIスレッド内から実行します。実行可能ファイルは、スレッドから戻ったときにUIスレッドから実行されます。

0
Pixel