我在开发javafx时遇到问题,我发现latch
对JavaFx没有影响,例如,在以下代码中:
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));
}
}
因为我设置了一个锁存器来阻止latch.await();
中的JavaFx主线程,并希望可调用线程fibCallable
首先输出内容:所以我希望:
Why, am I first?
Say 'Hello World'
但实际输出相反:
Say 'Hello World'
Why, am I first?
为什么呢?和解决方案?
答案 0 :(得分:2)
Platform.runLater()
提交要在FX应用程序线程上执行的runnable。 start()
方法也在FX应用程序线程上执行。因此,使用Runnable
提交的Platform.runLater()
在该线程上已经执行的任何内容完成之前无法执行。
所以你在后台启动你的fibThread
,然后立即等待锁存:这会阻止FX应用程序线程。 fibThread
做了一些工作,然后提交了对(阻止的)FX应用程序线程的调用。然后fibThread
释放锁存器:当前阻止的FX应用程序线程解除阻塞并完成当前方法调用(将文本"Say Hello World"
附加到文本区域并显示该阶段),并在此之后的某个时刻提交给Platform.runLater()
的runnable在同一个线程上执行。
“快速而肮脏”的修复只是将第二次调用包裹在另一个txtOut.appendText(...)
的{{1}}中:
Platform.runLater()
这保证可以正常工作,因为传递给Platform.runLater(() -> txtOut.appendText("\n Say 'Hello World'"));
的runnables保证按照它们传递的顺序执行,倒计时锁存器在两次调用{{}之间建立“before-before”关系{1}}。
但请注意,您通过调用Platform.runLater()
来阻止FX应用程序线程,这是不好的做法(并且会延迟显示阶段直到后台线程完成)。你应该把调用Platform.runLater()
和第二个latch.await()
放在另一个后台线程中。另请注意,您根本不需要锁存器,因为您已经有latch.await()
,并且您可以等待其结果(这相当于等待锁存器)。所以你可以做到
Platform.runLater()
最后,请注意JavaFX有自己的concurrency API,它直接支持FX应用程序线程上的各种回调。这个API通常意味着你可以避免用闩锁和锁等弄脏手。