2011-01-14 24 views
36

データをダウンロードするスレッドがあり、データをロードする前にダウンロードが完了するまで待つ必要があります。これを行う標準的な方法はありますか?Javaスレッドが終了するのを待つ

詳細:

私はURL(直列化されたPOJO)からデータを取得ダウンロードクラスを持っています。ダウンロードはRunnable and Observableです。ダウンロードしたバイト数とダウンロードサイズを記録します。ユーザーに進捗状況を表示するプログレスバーがあります。 GUIはダウンロードを観察してプログレスバーを更新します。

POJOがダウンロードされると、私はそれを取得して次のステップに移動したいと思います。各ステップは、前のステップが完了するのを待たなければなりません。問題は、ダウンロードスレッドを待つためにアプリケーションを一時停止する方法を考えることができないことです。ダウンロードが終了したら、データをオブジェクトとして返すdownload.getObject()を呼び出したいと思います。私はそれをキャストし、次のダウンロードで乗り越えることができます。

私は、ダウンロード用のURLを管理し、ダウンロードのすべての呼び出しを行うヘルパークラスを持っています。この呼び出しはgetObjectを呼び出し、キャストを行います。 Guiはhelper.getUser()を呼び出します。ヘルパーはスレッドの実行を開始し、キャストされたオブジェクトを返すことができるように、完了したら '知る'ようにします。

どのようなご提案ですか?私はこのデザインの最初の段階にありますので、私はそれを変更して喜んでいます。

ありがとうございました。

更新:

私はhttp://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#getに続き、スレッドが終了するまでブロックするために、モーダルを使用しました。コードは非常に乱雑で、私はこのアプローチが嫌いです。私は、ダウンロードプロセスのワークフローを処理するための「きれいな」方法を見つけようとし続けます。

答えて

51

Threadには、それを行う方法があります。 joinは、スレッドの実行が終了するまでブロックします。

+0

私は(参加しようとした)が、それは、更新からGUIを保ちました。私がスレッドを使用した理由は、ダウンロードが行われている間にGUIを更新し続けることでした。参加を呼び出すと、それが起こるのを止めます。 – Allan

+4

join()が動作します。 GUIが更新を停止する場合は、おそらくあなたが参加しているスレッドについてより詳細に記述する必要があります。私はEDTに参加しません。 – akf

+2

次に、スイングスレッドで 'join()'を呼び出さないようにする必要があります。これは、ダウンロードスレッドを担当する1つのスレッドを作成することで実行できます。これは本質的にあなたが忘れることのできるバックグラウンドワーカーです。ダウンロードが完了し、その時点で何をすべきかを知っているのはワーカースレッドです。スイングオブジェクトの編集がスイングスレッドで行われていることを確認するだけです。 SwingWorkerの場合は+1 – unholysampler

3

一般に、スレッドが終了するのを待つ場合は、join()を呼び出す必要があります。

4

SwingWorkerが提供するようなバックグラウンドスレッドでダウンロードを呼び出すと想像します。もしそうなら、次のコードを同じSwingWorkerのdoInBackgroundメソッドで順番に呼び出してください。

10

SwingWorkerにはdoInBackground()があり、タスクのプリフォームに使用できます。 get()を実行してダウンロードが完了するのを待つか、Swingworkerが完了したらイベントディスパッチスレッドで実行されるdone()メソッドをオーバーライドすることができます。

Swingworkerは、あなたが探している機能の多くを備えているため、ホイールを再構築する必要はありません。ダウンロードの進捗状況については、実行可能なオブザーバーの代わりにgetProgress() & setProgress()の方法を使用することができます。上記のdone()メソッドは、作業者が実行を終了してEDTで実行された後に呼び出されます。これにより、ダウンロードが完了した後にデータをロードできます。

+2

+1 – trashgod

1

どのようなご提案ですか?私はSwingWorkerに従った...コードは非常に乱雑で、私はこのアプローチが気に入らない。この単純example又はこの関連exampleで示唆したように完了を待つ代わりget()

は、中間結果を表示するprocess()setProgress()を使用します。

36

java.util.concurrentパッケージのCountDownLatchを使用できます。これは、待機中のスレッドで実行を続行する前に、1つ以上のスレッドが完了するのを待つときに非常に便利です。

例えば、3つのタスクを待っているが、完了するために:

CountDownLatch latch = new CountDownLatch(3); 
... 
latch.await(); // Wait for countdown 

他のスレッド(s)はそのタスクを完了し、その後、各コールlatch.countDown()。カウントダウンが完了すると、この例では3つが実行されます。

+0

@アルゾイドと同じ問題。 GUIスレッドが機能しなくなります。 –

+0

GUIのない​​アプリに最適です。 – JRichardsz

0

join()メソッドを使用すると、あるスレッドが別のスレッドの完了を待つことができます。ただし、スリープと同様に、ジョインはOSによってタイミングが異なるため、指定した時間だけジョインを待つ必要はありません。

1

join()方法のより良い代替方法は、ある期間にわたって進化してきた。

ExecutorService.html#invokeAllのいずれかです。

すべての完了時にステータスと結果を保持している先物のリストを返す、指定されたタスクを実行します。 Future.isDone()は返されたリストの各要素について真です。

完了したタスクは、通常どおりまたは例外をスローすることによって終了する可能性があることに注意してください。この操作の進行中に指定されたコレクションが変更された場合、このメソッドの結果は未定義です。

ForkJoinPoolまたはExecutors.html#newWorkStealingPoolは、同じ目的を達成するための他の選択肢を提供します。

例のコードスニペット:

import java.util.concurrent.*; 

import java.util.*; 

public class InvokeAllDemo{ 
    public InvokeAllDemo(){ 
     System.out.println("creating service"); 
     ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 

     List<MyCallable> futureList = new ArrayList<MyCallable>(); 
     for (int i=0; i<10; i++){ 
      MyCallable myCallable = new MyCallable((long)i); 
      futureList.add(myCallable); 
     } 
     System.out.println("Start"); 
     try{ 
      List<Future<Long>> futures = service.invokeAll(futureList); 
     }catch(Exception err){ 
      err.printStackTrace(); 
     } 
     System.out.println("Completed"); 
     service.shutdown(); 
    } 
    public static void main(String args[]){ 
     InvokeAllDemo demo = new InvokeAllDemo(); 
    } 
    class MyCallable implements Callable<Long>{ 
     Long id = 0L; 
     public MyCallable(Long val){ 
      this.id = val; 
     } 
     public Long call(){ 
      // Add your business logic 
      return id; 
     } 
    } 
} 
0

あなたはすべてのスレッドを終了するのを待つためにjoin()を使用することができます。スレッドの作成時には、スレッドのすべてのオブジェクトをグローバル配列に保持します。それは以下のようなループの中でそれを維持した後:完全な詳細については、こちらを

for (int i = 0; i < 10; i++) 
{ 
    Thread T1 = new Thread(new ThreadTest(i));     
    T1.start();     
    arrThreads.add(T1); 
} 

for (int i = 0; i < arrThreads.size(); i++) 
{ 
    arrThreads.get(i).join(); 
} 

チェック:http://www.letmeknows.com/2017/04/24/wait-for-threads-to-finish-java

関連する問題