2017-05-10 2 views
0

ich ein Problem auftreten javafx in der Entwicklung, finde ich latch hat keine Auswirkung in JavaFx zum Beispiel in dem folgenden Code:Wie Latch in javafx keine Wirkung hat?

public class JavafxLatchDemo1 extends Application { 

    @Override 
    public void start(Stage primaryStage) throws InterruptedException { 
     CountDownLatch latch = new CountDownLatch(1); 
     TextArea txtOut = new TextArea(); 

     StackPane root = new StackPane(); 
     root.getChildren().add(txtOut); 

     Scene scene = new Scene(root, 300, 250); 

     //invoke rpc function 
     Callable<Integer> fibCall = new fibCallable(latch, txtOut); 
     FutureTask<Integer> fibTask = new FutureTask<Integer>(fibCall); 
     Thread fibThread = new Thread(fibTask); 
     fibThread.start(); 
     latch.await(); //阻塞等待计数为0 


     txtOut.appendText("\n Say 'Hello World'"); 
     primaryStage.setTitle("Hello World!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 
} 

class fibCallable implements Callable<Integer>{   
    CountDownLatch latch; 
    TextArea txtInput; 

    fibCallable(CountDownLatch mylatch, TextArea txtIn){ 
     latch = mylatch; 
     txtInput = txtIn; 
    } 

    @Override 
    public Integer call() throws Exception { 
     int temp1=1,temp2=0; 

     System.out.println("Client will pay money for eshop"); 

     for(int i=0; i<10; i++){ 
      temp1 = temp1 + temp2; 
      temp2 = temp1; 
     } 
     System.out.println("Client already decide to pay money for eshop"); 

     Platform.runLater(()->{ 
      txtInput.appendText("\nWhy, am I first?"); 

     }); 
     latch.countDown(); //计数减1 

     return (new Integer(temp1)); 
    } 
} 

Da ich einen Riegel gesetzt JavaFx Hauptthread zu stoppen in latch.await();, und wollen das aufrufbare Thread fibCallable Ausgang der Inhalt zuerst: so erwarte ich:

Why, am I first? 
Say 'Hello World' 

aber die wirkliche Ausg ut ist das Gegenteil:

Say 'Hello World' 
Why, am I first? 

warum? und eine Lösung?

Antwort

2

Platform.runLater() übermittelt eine ausführbare Datei, die auf dem FX-Anwendungs-Thread ausgeführt werden soll. Die Methode start() wird auch auf dem FX-Anwendungs-Thread ausgeführt. So kann die Runnable, die Sie mit Platform.runLater() eingereicht haben, nicht ausgeführt werden, bis alles, das bereits an diesem Thread ausgeführt wird, abgeschlossen ist.

So starten Sie Ihre fibThread im Hintergrund und warten dann sofort auf den Latch: Dies blockiert den FX Application Thread. Die fibThread macht ein bisschen Arbeit und sendet dann einen Anruf an den (blockierten) FX-Anwendungs-Thread. Dann gibt fibThread den Latch frei: Der aktuell blockierte FX-Anwendungs-Thread hebt den aktuellen Methodenaufruf auf und beendet ihn (Anfügen des Texts "Say Hello World" an den Textbereich und Anzeigen der Phase), und zu einem späteren Zeitpunkt wird der Runnable an Platform.runLater() übergeben Gleicher Thread.

A „quick and dirty“ fix ist einfach um den zweiten Anruf txtOut.appendText(...) in einem anderen Platform.runLater() zu wickeln:

Platform.runLater(() -> txtOut.appendText("\n Say 'Hello World'")); 

Diese Arbeit ist garantiert, weil Runnables zu Platform.runLater() weitergegeben werden garantiert in der Reihenfolge ausgeführt werden, in dem sie übergeben werden, und der Countdown-Latch stellt eine "Vor-Vor" -Beziehung zwischen den zwei Aufrufen an Platform.runLater() her.

Beachten Sie jedoch, dass Sie den FX Application Thread mit dem Aufruf latch.await() blockieren, was eine schlechte Übung ist (und die Anzeige der Phase verzögert, bis der Hintergrundthread abgeschlossen ist). Sie sollten den Anruf wirklich zu latch.await() zusammen mit dem zweiten Platform.runLater() in einem anderen Hintergrundthread setzen. Beachten Sie auch, dass Sie den Latch überhaupt nicht benötigen, da Sie bereits eine FutureTask haben und Sie einfach auf sein Ergebnis warten können (dies entspricht dem Warten auf den Latch). So können Sie tun

import java.util.concurrent.Callable; 
import java.util.concurrent.FutureTask; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.scene.Scene; 
import javafx.scene.control.TextArea; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class JavafxLatchDemo1 extends Application { 

    @Override 
    public void start(Stage primaryStage) throws InterruptedException { 
//  CountDownLatch latch = new CountDownLatch(1); 
     TextArea txtOut = new TextArea(); 

     StackPane root = new StackPane(); 
     root.getChildren().add(txtOut); 

     Scene scene = new Scene(root, 300, 250); 

     //invoke rpc function 
//  Callable<Integer> fibCall = new fibCallable(latch, txtOut); 
     Callable<Integer> fibCall = new fibCallable(txtOut); 
     FutureTask<Integer> fibTask = new FutureTask<Integer>(fibCall); 
     Thread fibThread = new Thread(fibTask); 
     fibThread.start(); 
//  latch.await(); //阻塞等待计数为0 


     new Thread(() -> { 
      try { 
       // wait for fibTask to complete: 
       fibTask.get(); 
       // and now append text to text area, 
       // but this now must be done back on the FX Application Thread 
       Platform.runLater(() -> txtOut.appendText("\n Say 'Hello World'")); 
      } catch (Exception ignored) { 
       // ignore interruption: thread is exiting anyway.... 
      } 
     }).start(); 
     primaryStage.setTitle("Hello World!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 

    class fibCallable implements Callable<Integer>{   
//  CountDownLatch latch; 
     TextArea txtInput; 

     fibCallable(TextArea txtIn){ 
      txtInput = txtIn; 
     } 

     @Override 
     public Integer call() throws Exception { 
      int temp1=1,temp2=0; 

      System.out.println("Client will pay money for eshop"); 

      for(int i=0; i<10; i++){ 
       temp1 = temp1 + temp2; 
       temp2 = temp1; 
      } 

      System.out.println("Client already decide to pay money for eshop"); 

      Platform.runLater(()->{ 
       txtInput.appendText("\nWhy, am I first?"); 

      }); 
//   latch.countDown(); //计数减1 

      return (new Integer(temp1)); 
     } 
    } 
} 

Schließlich ist zu beachten, dass JavaFX eine concurrency API seiner eigenen hat, die direkt verschiedene Rückrufe auf dem FX Anwendung Gewinde unterstützt. Diese API bedeutet normalerweise, dass Sie vermeiden können, Ihre Hände mit Schlössern und Schlössern etc. schmutzig zu machen.

+0

tnanks, Sie sind gut –

+1

@EastJiang Markieren Sie die Antwort als richtig, wenn sie die Frage beantwortet –

Verwandte Themen