【发布时间】:2016-01-13 23:16:21
【问题描述】:
当我需要在 JavaFX 线程中做不定数量的工作而不阻塞用户界面时,我使用这个类
public class AsyncWhile {
private final IntPredicate hook;
private int schedCount = 0;
private boolean terminated = false;
private int callCount = 0;
private static final int schedN = 1;
public AsyncWhile(IntPredicate hook) {
this.hook = hook;
schedule();
}
public void kill(){
terminated = true;
}
private void schedule(){
while(schedCount < schedN){
Platform.runLater(this::poll);
schedCount++;
}
}
private void poll(){
schedCount--;
if(!terminated){
terminated = !hook.test(callCount++);
if(!terminated){
schedule();
}
}
}
}
喜欢这个
asyncWhile = new AsyncWhile(i -> {
// return false when you're done
// or true if you want to be called again
});
// can asyncWhile.kill() should we need to
(
如果您需要更具体的示例,这里我从 InputStream 一次读取一行,然后解析并显示从该行解析的图:
asyncWhile = new AsyncWhile(i -> {
String line;
try {
if((line = reader.readLine()).startsWith(" Search complete.")){ // it so happens that this reader must be read in the JavaFX thread, because it automatically updates a console window
return false;
} else {
Task<MatchPlot> task = new ParsePlotTask(line);
task.setOnSucceeded(wse -> {
plotConsumer.accept(task.getValue());
// todo update progress bar
});
executorService.submit(task);
return true;
}
} catch (IOException ex) {
new ExceptionDialog(ex).showAndWait();
return false;
}
});
)
像这样链接runLaters 感觉就像是一种黑客行为。解决此类问题的正确方法是什么? (“这种问题”是指可以通过简单的 while 循环解决的问题,如果不是因为它的内容必须在 JavaFX 线程中运行,而不会使 UI 无响应。)
【问题讨论】:
-
我不太确定如何回答您的问题:我将使用
Taskdocumentation 中的PartialResultsTask示例来解决您最后描述的示例问题。但请注意,您的AsyncWhile类中存在细微的线程错误:terminated需要声明为volatile,因为它是从多个线程访问的,并且schedCount需要在synchronized块中访问,或者需要替换为AtomicInteger。似乎您正在尝试重新发明轮子... -
@James_D 如果列出的所有代码都在 JavaFX 线程中运行,如何从多个线程访问
terminated? -
您必须假设
kill()只从 FX 应用程序线程调用。您的代码不会强制执行此操作,但如果这是真的,那么terminated不需要是volatile。不过,鉴于您编写此类的一般情况,并且鉴于kill()不太可能是性能关键操作,您可能应该使该线程安全。 -
@James_D 这是一个单线程类。如果其中有任何细微的错误,我将不胜感激。
-
好吧,我当时误会了。我假设(因为你已经调用了
Platform.runLater(...))这是打算从后台线程中使用的。
标签: java multithreading asynchronous javafx javafx-8