2016-10-05 12 views
0

こんにちは私はSwingWorkerを使ってスイングアプリのGUIを更新する方法を学びました。2人の同時スイングワーカーのdone()メソッドが正しい順序でEDTで実行されるようにするにはどうすればよいですか?

私は2つのスイングワーカーが同時に実行できる(それぞれが別のボタンから起動される)場合、EDTで完了メソッドが呼び出されていることを確認する方法(GUIを更新する)彼らは解雇されましたか?

私の所見とアイデア: 私はdoInBackground()メソッドをロックに同期させて、処理を続行する前にもう一方のタスクを完了するまで待たなければならないことを確認しました。問題は、(2番目のワーカーが同期ブロックで待機している間に)swingworker_1がdoInBackground()を終了するのを見ることができましたが(2番目のワーカーが同期ブロックで待機しています)、swingworker_2のdoneメソッドはEDT swingworker_2の後に終了しても、swingworker_1のdoneメソッドの前に。私はdoInBackground()が返る直前にpublishを使用することを考えましたが、これはいつもうまくいくようですが、最終的な結果ではなく中間結果に使用されるように思われるので、悪い習慣かもしれません。もう1つの可能性は、返す前にguiを更新するためにdoInBackground()内でSwingUtilities.invokeLaterを使用することですが、やはり悪い習慣であるかもしれません。前もって感謝します。

最初のボタンを押す

私が使用し、テストした後、すぐに第二1:

//Code that runs in the first button 
    SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() { 

     @Override 
     protected Void doInBackground() throws Exception { 
      synchronized (lock) { 
       System.out.println("Thread 1"); 

       Thread.sleep(1000); 
       return null; 
      } 

     } 

     @Override 
     protected void done() { 

      System.out.println("Done with thread 1 "); 
      //update GUI  
     } 

    }; 
    swingworker.execute(); 



    //Code that runs in the second button 
    SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() { 

     @Override 
     protected Void doInBackground() throws Exception { 
      synchronized (lock) { 
       System.out.println("Thread 2"); 

       return null; 
      } 

     } 

     @Override 
     protected void done() { 
      System.out.println("Done with thread 2 "); 
      //update GUI 
     } 

    }; 
    swingworker.execute(); 

UPDATE:ちょうど私が(swingworker_1またはswingworker_2)最初に起動する人にかかわっていないです明確にするだけによって異なりボタンが最初に押されるはずです。私が保証したいのは、ボタンからのワーカーが最初に実行された場合(つまり、ワーカーがdoInBackground()メソッドで同期化されて終了する場合)、EDTのguiを更新するためにエンキューする必要がある。私が見いだしたことは、たとえ作業者が同期していても、後で作業を開始する作業者が後で最初の作業の前にGUIを更新することがあっても、必ずしもそうなるとは限りません。

+1

を私は疑問に思います?これらの労働者は何をしており、あなたのプログラムは何をしていますか? –

+1

私自身、 'done()'メソッドの使用を避け、通常はPropertyChangeListenersを使ってワーカーの状態変更を待ち受けます。これにより、SwingWorkerはGUI固有の呼び出しを行う必要がなくなり、またGUIや呼び出しコードについての知識を持つことができます。 –

+1

あなたのコードでは、第1のワーカーが第2のものより前に 'ロック 'のモニタを取得することを保証する何も表示されません。 –

答えて

0

あなたは、労働者があなたのサンプルコードあたりのロックに同期させる、とあなたはdoInBackground()以外SwingWorkerdone()の他の機能のいずれかを使用していない場合、彼らは、それが簡単かもしれなる、逐次実行するとOKであれば単一のスレッド・エグゼキュータを使用し、SwingUtilities.invokeLater(...)を使用してGUI上に結果を提示することができます。

このようにすると、エグゼキュータに送信されたものが、送信された順に実行されることが保証されます。

これはあなたのために働く場合、あなたはこのような何かを試みることができる:1の場合、この順序は非常に重要である理由:あなたはXYの問題を説明していて、多くを教えてくださいすることを要求する場合

final ExecutorService executor = Executors.newSingleThreadExecutor(); 

// Code that runs in the first button 
Runnable worker1 = new Runnable() { 
    @Override 
    public void run() { 
    System.out.println("Thread 1"); 
    try { 
     Thread.sleep(1000); 
    } catch (InterruptedException e) { 
     e.printStackTrace(System.err); 
    } 
    SwingUtilities.invokeLater(this::updateGUI); 
    } 

    private void updateGUI() { 
    System.out.println("Done with thread 1"); 
    //update GUI 
    } 
}; 
executor.execute(worker1); 

// Code that runs in the second button 
Runnable worker2 = new Runnable() { 
    @Override 
    public void run() { 
    System.out.println("Thread 2"); 
    SwingUtilities.invokeLater(this::updateGUI); 
    } 

    private void updateGUI() { 
    System.out.println("Done with thread 2"); 
    //update GUI 
    } 
}; 
executor.execute(worker2); 
+0

こんにちはmsandiford、これは確かにあなたが労働者が次々に実行すると言っているように動作し、彼らは戻る前にGUIを更新するためにエンキューします。これを適応させるには、button1のworker1とbutton2のworker2を実行します。私が私の質問で最初に言ったように、私はスイングワーカーのdoInBackground()内のinvokelaterを使うことも同様に働くと確信しています。そして、私は出版がトリックもやっていると思っています。理由?それはちょうど奇妙なデザインのように完了しなければならないことは、労働者が終わるのと同じ順序で待ち行列に入れる必要はない。 – Cluster

+0

'doInBackground'で' synchronized'ブロックを使用し、synchronizedブロック内で 'invokeLater'を呼び出すことができますが、最終的に' SwingWorker'はマルチスレッドエグゼキュータを使用します。ほぼ同時にSwingWorkersが提出されました。作業者の投稿がGUIボタンをクリックすることに基づいていることを考えると、これはあなたのユースケースにとっては重要ではないかもしれません。 – msandiford

+0

正確にはmsandifordですが、まず最初に実行される人は関係ありません。最初に実行されるものがGUIの更新を最初にエンキューします。それはinvokelater、あなたのアプローチ(途中でいいと賢い離れている)またはスイングワーカーの同期doInBackground()内で、この順序が確実に満たされているようです。これに対して、doneメソッドではこれを保証することはできません。前に提案されたpropertyChangeListenerもまた洗練された解決策かもしれませんが、doInBackground()の終了と完了ステータスの変更の間に遅延があるかもしれないので、適切な順序を保証しないかもしれません。 – Cluster

関連する問題