我正在开发一个 JavaFX 桌面应用程序,我有一个按钮应该从嵌入式设备的内存中读取并将其打印到 JSON 中。我已经实现了一个执行此操作的任务,并且该任务作为参数传递给按钮事件处理程序中的新线程。问题是,这只有效一次。此后,即使单击按钮时生成了新线程,也不会再次调用任务的 call() 方法。这是代码:
任务定义:
Task readValDaemon = new Task<Void>() {
@Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
线程创建:
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
Thread readValThread = new Thread(readValDaemon);
readValThread.setDaemon(true);
readValThread.start();
}
});
最佳答案
正如其他答案中所观察到的, Task
是 FutureTask
的实现。来自Task
文档:
As with
FutureTask
, aTask
is a one-shot class and cannot be reused. SeeService
for a reusableWorker
.
所以你不能重用任务。第二次及后续尝试运行它只会默默地失败。
您可以每次直接创建一个新任务:
private Task<Void> createReadValTask() {
return new Task<Void>() {
@Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
}
然后做
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
Thread readValThread = new Thread(createReadValTask());
readValThread.setDaemon(true);
readValThread.start();
}
});
您还可以考虑使用 Service
,它是为重用而设计的。它基本上封装了“每次创建一个新任务”的功能,但添加了许多有用的 UI 回调。一个Service
还为您管理一个线程池(通过 Executor
),因此您不再需要担心可能创建太多线程。 (如果您想控制它,也可以指定Executor
。)
所以,例如:
Service<Void> readValDaemon = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
}
};
然后
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
readValThread.restart();
}
});
如果在服务已经运行时单击鼠标,这将自动取消已经运行的任务,并重新启动一个新任务。如果需要,您可以添加检查,或绑定(bind) disable
readData
的状态到Service
的状态,如果你愿意的话。
关于JavaFx 新线程,具有相同的任务作为输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49275063/