2017-07-10 17 views
0

別のスレッドでの計算の実行に関連する私のやや初心者の質問は申し訳ありませんが、私はC++のプログラマーです。別のスレッドと呼び出し可能なスレッドと実行可能なスレッドとmulitasking

大きな画像を処理するには計算コストが高いタスクがあります。処理中に私は自分のソフトウェア(ズーム操作を含む)で作業できるようにしたいと考えています。あなたのadviceに基づいて

(手順では、データを返す - 新しいイメージ)呼び出し可能インターフェースが使用されている :

public class B implements Callable<BufferedImage> { 
    private boolean c; 

    public B (boolean c) { this.c = c; } 

    public BufferedImage call() { 
     //Some operations 
     if (!c) 
      return null; 
     return new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); 
    } 
} 

は当初、エグゼキュータのサービスが作成されます。

ExecutorService exe = Executors.newFixedThreadPool(2); 
B b = new B(true); 

をその後、将来は返されます:

Future<BufferedImage> res = exe.submit(b); 

最後に、データを待っています:

BufferedImage img = res.get(); 

残念ながら、この実装は予期したとおりに動作しません。それは別のスレッドで動作しますが、「応答」はメインウィンドウに返されず、の計算中にソフトウェアを正しく使用することができません。

。したがって、私は

try 
{ 
    BufferedImage img_proj = results.get(5, TimeUnit.MILLISECONDS); 
} 

catch (Exception e) 
{ 
    results.cancel(true); 
    e.printStackTrace(); 
} 

ように、get()メソッドを変更しようとしたが、TimeoutExceptionが表示されます。 ...

Thread t = new Thread(b); 
t.start(); 

と予想されるようにマルチタスク作品で

public class B implements Runnable{ 
    private boolean c; 
    private Runnable f; 

    public B (boolean c_, Runnable f_) { c = c_; f = f_;} 

    public BufferedImage process() { 
      //Some operations 
      BufferedImage output = null; 
      if (c) output = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); 
      return output; 
    } 

    public void run() { process();} 
} 

一緒に戻って、Runnableインタフェースを使用してコードを書き換え

だから、私の質問は:それは「調整」またはする必要がありますさらにCallableインターフェイスを調整してください。もしそうなら、どのように?

答えて

1

実行者サービスを使用することをお勧めします。

exe.submit(()->{ 
    BufferedImage img = res.get(); 
    uiRelatedMethod(img); 
}); 

あなたのGUIスレッドはブロックされず、バッファリングされたイメージが利用可能になると通知されます。もちろん、try/catchブロックを使用する必要があります。

+0

@ matt:ありがとうございます。ここで何を意味するのですか?私のコードでは、Future resはサブミットプロシージャの結果を表しています.... – justik

+0

はい、正確にあなたの例のresです。単にres.get()を呼び出すのではなく、あなたのエグゼキュータにタスクとしてres.getを送信してください。 – matt

+0

@ matt:これは素晴らしいことです...私の現在のコードをほとんど変更することなく。ありがとう。 – justik

2
BufferedImage img = res.get(); 

これは、画像が計算されるまで、呼び出されたスレッド全体をブロックします。 メインまたはUIメッセージディスパッチスレッドからこれを呼び出すと仮定します。そのため、UIはブロックされています。

  • は、イメージが完全に計算されたときに、あなたのUIを通知する通知メカニズムを実装します。

    は、これを解決するには、いくつかの方法があります。たとえば、リスナをBのコンストラクタに渡して格納し、計算の最後にリスナに通知します。

  • あなたの先物が完了したら定期的にチェックして(isDone())、アクションを実行します。
  • Java並行性に関する通知インフラストラクチャを提供するいくつかのユーティリティライブラリもあります。

EDIT:一例として要求されました:

あなたの完全なアプリケーション、あるいは少なくともその技術スタックを知らなくても良い例を与えることは困難です。

は(私は自分のアプリケーションで行うだろう)自分のインタフェースを実装しないようにするには、私はJavaののChangeListenerインターフェイスを再使用します。

あなたのBクラスが拡張
public void myButtonWasClicked() { 
    // all your stuff setting up executor... 

    // yes, this could be written much shorter with Java 8 
    ChangeListener myChangeListener = new ChangeListener() { 
    public void stateChanged(ChangeEvent evt) { 
     handleImageReady((BufferedImage)evt.getSource()); 
    } 
    } 

    B b = new B(true, myChangeListener); 
    exe.submit(b); 
} 

public class B implements Callable<BufferedImage> { 
    private boolean c; 

    private ChangeListener listener; 

    public B (boolean c, ChangeListener listener) { this.c = c; this.listener = listener; } 

    public BufferedImage call() { 
     //Some operations 
     if (!c) 
      return null; 
     BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); 
     // pass finished image to listener who will handle in the UI 
     listener.stateChanged(new ChangeEvent(img)); 
     return img; // as nobody will consume this any longer, you could as well switch back to Runnable instead of Callable... 
    } 
} 

ますのでご注意くださいこれはJavaの初心者のための本当に大まかな例です。改善すべきことがたくさんあるだろう。たとえば、Executorサービスをどこかでシャットダウンする必要があります。

+0

@フロリアン:あなたの答えに感謝します。私は親切にいくつかの例を求めることができますか? – justik

+0

@ Florian:あなたの実例をありがとうございました。今、理解しやすいように見えます。 – justik

関連する問題