在JavaFXUI中使用应返回结果的线程
我可能在这里遗漏了一些东西,但我会尝试解释我想要实现的目标,然后有人告诉我我做错了(我是:),并为我指出正确的方向 我使用的是JavaFX2.0,但我认为这个问题将适用于Swing或任何UI框架 我想为我的应用程序开发一个简单的启动屏幕,当启动屏幕启动时,我想有一个消息标签,用于更新用户在配置应用程序后端时发生的事情。我的应用程序启动有两个步骤,第一步使用Spring初始化应用程序上下文,然后初始化DB(JPA2.0/Hibernate/etc)。我的应用程序启动过程的第二部分将向数据库查询用于填充UI的初始数据。在关闭启动屏幕之前,这两个步骤都需要完成,在每个步骤之间,我希望更新启动屏幕中的标签,以让用户知道此时正在执行哪个阶段 我将其分解为以下使用JavaFX和按钮的简单程序,当按下按钮时,将创建一个新线程,启动另一个类,该类只对一个特定值执行一些计数,然后创建另一个线程来模拟启动过程的第二步,但我的问题是,第二个线程试图在第一个线程完成之前运行,结果运行到NPE 下面是一些强调此问题的简单代码的分解:在JavaFXUI中使用应返回结果的线程,java,swing,user-interface,thread-safety,javafx-2,Java,Swing,User Interface,Thread Safety,Javafx 2,我可能在这里遗漏了一些东西,但我会尝试解释我想要实现的目标,然后有人告诉我我做错了(我是:),并为我指出正确的方向 我使用的是JavaFX2.0,但我认为这个问题将适用于Swing或任何UI框架 我想为我的应用程序开发一个简单的启动屏幕,当启动屏幕启动时,我想有一个消息标签,用于更新用户在配置应用程序后端时发生的事情。我的应用程序启动有两个步骤,第一步使用Spring初始化应用程序上下文,然后初始化DB(JPA2.0/Hibernate/etc)。我的应用程序启动过程的第二部分将向数据库查询用于
public class Test extends Application
{
private LongTester lt;
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage)
{
Button btn = new Button();
final Label lblText = new Label("Starting");
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
new Thread(new ConstructorRunnable()).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable()).start();
lblText.setText("Finished");
}
});
HBox root = new HBox();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private class ConstructorRunnable implements Runnable
{
@Override
public void run()
{
lt = new LongTester();
}
}
private class MethodRunnable implements Runnable
{
@Override
public void run()
{
lt.countAgain();
}
}
private class LongTester
{
public LongTester()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Constructor: " + idx);
}
}
public Boolean countAgain()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Method: " + idx);
}
return Boolean.TRUE;
}
}
}
公共类测试扩展应用程序
{
私人Longtest lt;
公共静态void main(字符串[]args)
{
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage)
{
按钮btn=新按钮();
最终标签lblText=新标签(“开始”);
btn.setText(“说‘你好,世界’”);
btn.setOnAction(新的EventHandler()
{
@凌驾
公共无效句柄(ActionEvent事件)
{
新线程(新构造函数未知()).start();
lblText.setText(“更多加载?”);
新线程(新方法runnable()).start();
lblText.setText(“已完成”);
}
});
HBox根=新的HBox();
root.getChildren().add(btn);
场景=新场景(根,300,250);
setTitle(“你好,世界!”);
初级阶段。场景(场景);
primaryStage.show();
}
私有类构造函数Runnable实现可运行
{
@凌驾
公开募捐
{
lt=新Longtest();
}
}
私有类MethodRunnable实现Runnable
{
@凌驾
公开募捐
{
中尉再次倒数();
}
}
私人班龙特酒店
{
公共部门
{
对于(intidx=0;idx<1000000;idx++)
{
System.out.println(“构造函数:+idx”);
}
}
公共布尔计数()
{
对于(intidx=0;idx<1000000;idx++)
{
System.out.println(“方法:+idx”);
}
返回Boolean.TRUE;
}
}
}
有人能指出我的错误吗?要解决您的问题,您可以使用 这可以通过以下方式使用:
private class ConstructorRunnable implements Runnable {
CountDownLatch gate_ = null;
public ConstructorRunnable(CountDownLatch gate){
gate_ = gate;
}
@Override
public void run() {
lt = new LongTester();
gate_.countDown(); // Signal the second thread to start
}
}
private class MethodRunnable implements Runnable{
CountDownLatch gate_ = null;
public MethodRunnable(CountDownLatch gate){
gate_ = gate;
}
@Override
public void run(){
CountDownLatch.await(); // Wait for the first thread to finish
lt.countAgain();
}
}
现在可以这样使用:
CountDownLatch gate = new CountDownLatch(1);
new Thread(new ConstructorRunnable(gate)).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable(gate)).start();
lblText.setText("Finished");
另一方面:由于任务是连续的,为什么需要有多个线程?线程被设置为并行运行多个任务,而您的案例并不构成线程的用例,因为这些操作是连续的我建议使用来执行启动任务,并将进度消息返回到初始屏幕(类似于为先前创建的本例中的方法)。如果希望任务中的内容按顺序运行,只需使用一个线程而不是两个线程 任务的示例代码可能类似于:
final Task<Data> initTask = new Task() {
@Override protected Data call() throws InterruptedException {
updateMessage("Initializing Application");
MyApp.initializeAppContext();
updateMessage("Loading Data");
Data data = DB.loadData();
updateMessage("Data Loaded");
return data;
}
showSplash(initStage, initTask);
new Thread(initTask).start();
showMainStage(initTask.valueProperty());
final Task initTask=新任务(){
@Override protected Data call()引发InterruptedException{
更新消息(“初始化应用程序”);
MyApp.initializeAppContext();
更新消息(“加载数据”);
Data Data=DB.loadData();
更新消息(“加载的数据”);
返回数据;
}
showSplash(initStage、initTask);
新线程(initTask.start();
showMainStage(initTask.valueProperty());
“另一方面,由于任务是连续的,为什么需要多个线程?”这就是我出错的地方…出于某种原因,我在脑海中一直认为这两个任务都需要在不同的线程中运行,而你完全正确,我的用例不要求它们在不同的线程中运行。我也不知道倒计时闩锁类,所以我感谢你提供的这一点信息。干杯@jewelsea我查看了using任务之前,但我的问题是,我使用了2个线程,而只需要1个线程,您也指出了这一点,由于JavaFX代码,我接受您的答案。再次感谢。