2016-07-01 10 views
1

FXアプリケーションスレッドで実行されている簡単なJavaFXアプリケーションを作成しました。 FXアプリケーションのGUIコントロールを一定の間隔で更新するには、Platform.runLater()と呼ぶ別のスレッド(FXスレッドではない)上で実行される無限ループでバックグラウンド処理が必要です。 FX Guiアプリケーションを閉じると、バックグラウンドスレッドはその実行を続けます。FXスレッドがJavaで終了した場合にスレッドを終了する最も効率的な方法

FXスレッドが終了した後に、バックグラウンドスレッドを終了させるためには、私は今、バックグラウンドスレッドでwhileループでfxThread.isAlive()を使用しています。 この方法では、whileループ条件がfalseになるとFXスレッドが終了すると、バックグラウンドスレッドは自動的に終了します。

これは悪い選択ですか?同じタスクを達成するための代替的かつ効率的な方法は何ですか?ない非常に最善の解決策のスレッドがfxThread.isAlive()に合格し、時間にしている一方で、最悪のシナリオでは原因は、あなたのfxThreadは、死ぬかもしれない入るPlatform.runLaterを与えるそのfxThread.isAlive()を呼び出すことによって

//imports 
public class SimpleClockFX implements Application{ 
Thread fxThread; 
//other variables 

@Override 
public void start(Stage primaryStage){ 
    fxThread = Thread.currentThread(); 

    //other stuff... 

    new Thread(()->{ 
    //logic... 
     while(fxThread.isAlive()){ 
      //logic... 
        Platform.runLater(()->{ 
         //update gui controls 
        }); 
     } 
    }).start(); 

}

+0

おそらくFXアプリケーションの終了方法とバックグラウンドスレッドの起動方法については、http://codereview.stackexchange.com/ – ManoDestra

+0

を参照してください。また、 'thread.setDaemon(true)'を渡していないとします。 – AntJavaDev

+0

あなたの質問にコメントを入れないでください。 – AntJavaDev

答えて

2

これはあなたのケースに対する適切な終了である場合を除いて例外です。

トップレベルステージでcloseイベントのリスナーを追加しようとします。

また、JVMや任意のカスタム終了メソッドを完全に終了するために、System.exit(0)を呼び出すこともできます(バックグラウンドスレッドがまだ実行中の場合は明示的に割り込みを発生させます)。

@Override 
    public void start(Stage primaryStage) 
    { 
     primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { 
      public void handle(WindowEvent we) { 
       System.out.println("Stage is closing"); 
       System.exit(0); 
      } 
     }); 

     primaryStage.setTitle("Hello World!"); 
//  add your components 
     primaryStage.show(); 
//  not daemon 
     new Thread(new CustomRunnable()).start(); 

    } 

    private static class CustomRunnable implements Runnable 
    { 
     public void run() 
     { 

      while(true){ 
//    long operation 
      } 
     } 
    } 

EDIT:lostsoul29コメント@を1として

、シナリオは産卵のスレッドがデーモンスレッドであることを行っていないことを意味します。任意のスレッドがデーモンとしてマークされている場合、カスタム終了/処理が必要になります。

+0

良いと思っています.... setOnCloseRequest存在する。 私はちょうど次のスニペットを追加しました: primaryStage.setOnCloseRequest((WindowEvent私たち) - > { System.exit(0); }); とwhileループ条件を "true"に更新しました...そして、それは仕事をうまくやっています。ありがとうございました:) –

+0

'System.exit(0)'は、生成されたすべての子スレッドを強制終了しません。順番に各スレッドを閉じて、アプリケーションを終了する必要があります。 – lostsoul29

+0

@ lostsoul29、あなたは質問/答えをはっきりと理解していないようです。まず、下記のリンクを参考にしてください。まだ問題が発生している場合は、新しい質問でお知らせください。 [スレッドライフサイクル](https://docs.oracle.com/cd/E82638_01/JJDEV/threading-in-database)htm#JJDEV-GUID-44A07CEA-EB31-4C69-9300-6068A63EC880)、[setDaemon()](https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setDaemon (ブール値) – AntJavaDev

2

スレッドは、単にスレッドにデーモンスレッドを作成し、終了時にクリーンアップを行う必要がない場合は、次のデーモンスレッドまたはユーザスレッドとして

thread.setDaemon(true)

マークこのスレッドを。 Java仮想マシンは、実行中のスレッドのみがすべてデーモンスレッドである場合に終了します。 このメソッドは、スレッドが開始される前に呼び出さなければなりません。あなたの処理スレッドがクリーンアップを行う必要がない場合setDaemon()を使用して

ははるかに最も簡単な方法であると推奨されているものである(例えば、それはアトミックコミットトランザクションを完了またはロールバックする必要はありません。 )アプリケーションが終了する前に。


あなたはそれが終了する前にスレッドのクリーンアップを実行する必要がある場合は、スレッドデーモンを作るが、その代わりに、スレッドの割り込みを行う割り込みを発行し、割り込みを処理できない方が良いです。例えば

ExecutorServiceを使用してスレッドを管理し、ExecutorServiceのJavadocので言及したのと同様の方法を使用したアプリケーションstop()方法であなたシャットダウンこと:shutdownNow()呼び出しは暗黙的に割り込みを送ること

void shutdownAndAwaitTermination(ExecutorService pool) { 
    pool.shutdown(); // Disable new tasks from being submitted 
    try { 
    // Wait a while for existing tasks to terminate 
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
     pool.shutdownNow(); // Cancel currently executing tasks 
     // Wait a while for tasks to respond to being cancelled 
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
      System.err.println("Pool did not terminate"); 
    } 
    } catch (InterruptedException ie) { 
    // (Re-)Cancel if current thread also interrupted 
    pool.shutdownNow(); 
    // Preserve interrupt status 
    Thread.currentThread().interrupt(); 
    } 
} 

注意あなたのスレッドは、あなたのスレッドプロセッサが割り込みを処理するように明示的にコーディングされていない限り有効ではありません。

典型的な実装では、Thread.interrupt()を介してキャンセルされるため、割り込みに応答しないタスクは決して終了しない可能性があります。

キャンセルが本当に機能していない、あなたはあきらめしたい場合は、System.exit()で上記のコードでSystem.err.println()文を置き換えることができます。

そして、あなたのスレッドのタスク・ロジックも中断に対処する必要があります。また

public class PrimeProducer extends Thread { 
    private final BlockingQueue<BigInteger> queue; 

    PrimeProducer(BlockingQueue<BigInteger> queue) { 
     this.queue = queue; 
    } 

    public void run() { 
     try { 
      BigInteger p = BigInteger.ONE; 
      while (!Thread.currentThread().isInterrupted()) 
       queue.put(p = p.nextProbablePrime()); 
     } catch (InterruptedException consumed) { 
      /* Allow thread to exit */ 
     } 
    } 

    public void cancel() { interrupt(); } 
} 

注意し、あなたがスレッドをサブクラス化されるのではなく、そうでない、その後、ライブラリ型コード用のRunnableを実装している場合上記のように、割り込みを飲み込むしたいのですが、(中断された状態を復元すると、ライブラリのコードのために望ましい理由をさらに理解するには、以下の「InterruptedExceptionあるの対処」読み)の代わりに、あなたは以下に似た割り込みステータスを復元したい:

public class TaskRunner implements Runnable { 
    private BlockingQueue<Task> queue; 

    public TaskRunner(BlockingQueue<Task> queue) { 
     this.queue = queue; 
    } 

    public void run() { 
     try { 
      while (true) { 
       Task task = queue.take(10, TimeUnit.SECONDS); 
       task.execute(); 
      } 
     } 
     catch (InterruptedException e) { 
      // Restore the interrupted status 
      Thread.currentThread().interrupt(); 
     } 
    } 
} 

も参照いくつかの参照文書(この答えでの情報の一部がコピーだったと貼り付け、そこから):

+0

それはかなり有益でした。どうもありがとうございます :) –

関連する問題