2013-04-28 9 views
22

これは一般的なJavaの質問であり、Androidの最初のものではありません。メインスレッドのコードをセカンダリスレッドから実行していますか?

私は、セカンダリスレッドのコンテキストから、メインスレッドでコードを実行する方法を知りたいと思います。たとえば、次のように

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を実行する必要があります。

EDIT:比較のためには - ここで私は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 
    }); 
}); 

ありがとう!

答えて

25

実行中の別のスレッドにコードを送信し、「やあ、そう、これをやって」と言う普遍的な方法はありません。メインスレッドは、仕事を受け取る仕組みがあり、仕事がするのを待っている状態にする必要があります。

ここでは、メインスレッドを設定して他のスレッドから作業を受け取り、到着したときに実行する簡単な例を示します。明らかに、実際にプログラムを終了する方法などを追加したいと思うでしょう。

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

ああ、実際には、この種のスレッドは、バックグラウンドスレッドを待っているのでメインスレッドがブロックされているので、バックグラウンドスレッドを使用する目的を破ると思います。それはかなりきちんとした仕組みのように見えます!私は今すぐキューについてもっと読むつもりです! – Javawag

+0

あなたは確かにメインスレッドが他の仕事をしているだけでなく、何もしないで間隔でキューをチェックすることができます。しかし、ある時点では自家製の価値があるのを止めるSwingは完全に良いツールを提供しています:) – Affe

+0

実際には、私がやっていることについてはかなり良いアイデアです - プロジェクトが実際に書かれた単純なゲームなのでSwingを使用していませんSlick2dエンジンを使用してください(それ以外の場合は正しいです;私はSwingの組み込みツールを使用します) – Javawag

17

あなたがAndroidを使用している場合は、ハンドラを使用してください。

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

私は 'runOnUIThread()'と呼ばれるメソッドがあることは知っていますが、すべての状況でコードが 'Activity'で書かれているわけではありません。この答えは私に多くの時間を節約しました。ありがとう! – ManuQiao

+0

Qはアンドロイドについてではなく、Androidタグも持っていません。 –

6

古い議論が、それはあなたがまた、先物でそれを行うことができ、メインスレッド(ないと反対方向)にリクエストを送信するの問題ですか。基本的な目的は、結果を得るために、それが終了すると、バックグラウンドで何かを実行することです:

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

あなたの意図は、バックグラウンドでいくつかのものを行うと、結果を取得する場合、あなたが言ったように、いくつかのキューを設定することができますプロセスをいくつかの先物に分割することもできます(すべてを一度に開始するか、必要に応じて新しいプロセスを開始することもできます)。メインスレッドで初期化されたマップまたはリストに各タスクを格納すると、いつでも必要な先物をチェックし、完了したら結果を得ることができます。

2

ほとんどのイベント駆動型の処理が行われる場所では、「ディスパッチスレッド」を使用することをお勧めします。 swingを使用している場合:

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

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

関連する問題