ExecutorService的JavaFX版本
我制作了一个Java实用程序,可以在x个精美的zip文件(twx)中搜索XML
最初这是一个命令行实用程序,没有线程
当我将其移动到使用JavaFX时,我遇到了冻结问题,然后将所有搜索移动到一个任务对象中进行修复
我需要一些方法来跟踪进度,所以我实现了progress属性和ProgressBar来跟踪进度
它工作得很好,但既然我已经是多线程的,为什么不为每个Zip搜索创建一个线程呢。不幸的是,这并没有起到很好的作用
为了保持跟踪,我创建了一系列任务,然后创建了一个处理这些任务的主任务。我使用progress和total属性来处理所有更新
这是密码
public class TextSearch {
final private SimpleDoubleProperty progress = new SimpleDoubleProperty();
final private SimpleDoubleProperty total = new SimpleDoubleProperty();
/**
*
* Kicks off a search. Creates a Task/Thread for each twx search.
* @return A task object that maintains all of the twx searches.
*
* @throws ZipException If the zip file is unreadable.
* @throws IOException If the file is unreadable.
* @throws JDOMException If the xml in the files are unreadable.
* @throws InvalidTWXFile If the twx is corrupt.
*/
public Task<?> executeSearch() throws ZipException, IOException, JDOMException, InvalidTWXFile {
//Loop through all registered twx files.
Iterator<TWExport> rit = registered.iterator();
Integer t = 0;
//Create a task for each search
final ArrayList<Task<?>> tasks = new ArrayList<Task<?>>();
while(rit.hasNext())
{
final TWExport twx = rit.next();
//Only run search if user selects to search it.
if(twx.getSearchEnabled())
{
Task<Void> task = new Task<Void>() {
@Override public Void call() {
informUser("Searching " + twx);
SearchResults proj = new SearchResults(twx);
searchResult.add(proj);
searchTwx(proj,twx);
twx.setResultCount(proj.getTotalCount());
informUser("Finished Searching " + twx);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
}
}
return null;
}
};
tasks.add(task);
t += twx.getObjects().size();
} else
{
informUser("Skipping " + twx);
}
}
total.setValue(t);
//Create the main thread that will hold all individual searches.
Task<Void> main = new Task<Void>() {
@Override
protected Void call() throws Exception {
startTime = new Date();
Iterator<Task<?>> it = tasks.iterator();
while(it.hasNext())
{
Thread t = new Thread(it.next());
t.start();
}
//Sometimes I get a hung thread in this loop
while(!progress.getValue().equals(total.getValue()))
{
updateProgress(progress.getValue(), total.getValue());
Thread.sleep(5000);
}
setEndTime(new Date());
return null;
}
};
new Thread(main).start();
return main;
}
/**
* Search through a twx file and add results to the project search results
* @param proj The parent SearchResults
* @param twx The TWExport to search
*/
private void searchTwx(SearchResults proj, TWExport twx) {
Iterator<TWObject> it = twx.getObjects().iterator();
//Iterate through the files and get the result
while(it.hasNext())
{
TWObject object = it.next();
progress.setValue(progress.getValue() + 1);
if(searchArtifacts.matcher(object.getName()).find())
{
SearchResults result = object.searchContents(searchStr);
if(result != null)
{
proj.add(result);
}
}
}
}
使用主线程似乎非常笨拙,有时在一次搜索10多个zip文件时,它会挂起在该循环中
在任务数量未知的情况下,有没有更好的方法来实现这一点?有没有像JavaFX ExecutorService这样的服务,我可以在其中添加一系列任务,启动它并监视progressProperty
# 1 楼答案
不需要特定于JavaFX的executor服务:常规的
java.util.concurrent.ExecutorService
工作得很好,因为Task
是FutureTask
的一个子类一旦有了任务列表,就可以根据每个任务的进度计算总体进度。例如,它可能只是所有进度的总和除以任务的数量。如果每个任务都有不同数量的项目要处理,那么您可能可以做一些更复杂的事情
以下是一个简单的SSCCE: