我正在研究JavaFX桌面应用程序,我有一个按钮,应从嵌入式设备的内存中读取并将其打印到JSON中。我已经实现了一个执行该操作的Task,并且此Task作为参数传递给按钮事件处理程序中的新线程。问题是,这只能工作一次。之后,即使在按钮单击时生成新线程,也不会再次调用Task的call()方法。这是代码:
任务定义:
42
46
线程创建:
Task readValDaemon = new Task<Void>() {
@Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
答案 0 :(得分:1)
正如在其他答案中所观察到的,Task
是FutureTask
的实现。来自Task
文档:
与
FutureTask
一样,Task
是一次性类,无法重复使用。有关可重复使用的Service
,请参阅Worker
。
因此您无法重复使用任务。第二次和后续尝试运行它将会无声地失败。
您每次都可以直接创建新任务:
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();
}
});
如果在服务已经运行时单击鼠标,则会自动取消已在运行的任务,并重新启动新任务。如果需要,您可以添加支票,或者将disable
状态readData
绑定到Service
的状态,如果您愿意的话。
答案 1 :(得分:0)
Task
是一种错误的工具。它非常有目的地只设计为运行一次,因为它是future的一种。它将结果(在您的情况下为null)存储为一种memoization,以避免执行比必要更多次的昂贵操作。所以Task
最适合需要进行昂贵计算一次的情况,通常你会想要在某一点上得到它的结果。
documentation for Task
非常彻底,所以我会给你一个阅读。
在您的情况下,只需使用普通Runnable
。您可以使用lambda表达式:
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event)
{
Thread readValThread = new Thread(() -> readDataHI(a, b, c));
readValThread.setDaemon(true);
readValThread.start();
}
});
另外,在现代Java中,手动创建线程并不算是非常好的做法。强烈考虑改为ExecutorService
。