- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我制作了一个 Java 实用程序,可以在 x 个精美的 zip 文件 (twx) 中搜索 XML。
最初这是一个命令行实用程序,没有线程。
当我将它移动到使用 JavaFX 时,我遇到了卡住问题,然后将所有搜索移动到任务对象中进行修复。
我需要一些方法来跟踪进度,因此我实现了 Progress 属性和 ProgressBar 来进行跟踪。
效果很好,但既然我已经是多线程的,为什么不为每个 Zip Search 创建一个线程。不幸的是,这并没有起到很好的作用。
为了保持跟踪,我创建了一个任务数组,然后创建了一个处理它们的主任务。我使用 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?
最佳答案
不需要特定于 JavaFX 的执行程序服务:常规 java.util.concurrent.ExecutorService
工作得很好,因为 Task
是 的子类 future 任务
。
获得任务列表后,您可以根据每个任务的进度计算总体进度。例如,它可能只是所有进度的总和除以任务数。如果每个任务都有不同数量的项目要处理,您可以做一些更复杂的事情。
这是一个简单的 SSCCE:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MultipleTaskTest extends Application {
private final ExecutorService exec = Executors.newFixedThreadPool(5, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t ;
});
private final Random rng = new Random();
@Override
public void start(Stage primaryStage) {
Label pendingTasksLabel = new Label();
Button button = new Button("Launch tasks");
TextArea log = new TextArea();
DoubleProperty progress = new SimpleDoubleProperty(1);
ProgressBar progressBar = new ProgressBar();
progressBar.progressProperty().bind(progress);
IntegerProperty pendingTasks = new SimpleIntegerProperty(0);
pendingTasksLabel.textProperty().bind(pendingTasks.asString("Pending Tasks: %d"));
button.disableProperty().bind(pendingTasks.greaterThan(0));
button.setOnAction(e -> {
int numTasks = rng.nextInt(5) + 4 ;
List<Task<Void>> tasks = new ArrayList<>();
for (int i = 0; i < numTasks; i++) {
tasks.add(createRandomTask());
}
// rebind progress:
progress.unbind();
progress.bind( new DoubleBinding() {
{
for (Task<Void> task : tasks) {
bind(task.progressProperty());
}
}
@Override
public double computeValue() {
return tasks.stream().collect(Collectors.summingDouble(
task -> Math.max(task.getProgress(), 0)
)) / numTasks;
}
});
log.appendText("Submitting "+numTasks+" tasks\n");
pendingTasks.set(numTasks);
// log state of each task:
tasks.forEach(task ->
task.stateProperty().addListener((obs, oldState, newState) -> {
log.appendText("\tTask "+newState+"\n");
// update pendingTasks if task moves out of running state:
if (oldState == Worker.State.RUNNING) {
pendingTasks.set(pendingTasks.get() - 1);
}
}));
tasks.forEach(exec::execute);
});
VBox root = new VBox(10, pendingTasksLabel, progressBar, log, button);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
VBox.setVgrow(log, Priority.ALWAYS);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
@Override
public void stop() {
exec.shutdownNow() ;
}
private Task<Void> createRandomTask() {
int numSteps = 100 + rng.nextInt(100);
return new Task<Void>() {
@Override
public Void call() throws Exception {
for (int i = 1; i <= numSteps; i++) {
Thread.sleep(50);
updateProgress(i, numSteps);
}
return null ;
}
};
}
public static void main(String[] args) {
launch(args);
}
}
关于JavaFX 版本的 ExecutorService,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33394428/
我有一个executorService,它不等待executorService部分完成,它直接返回返回值而不等待下面是我的代码:请查看我是否正确实现了executorService,并在需要时帮助我纠
我有一个运行在另一个执行器服务中的执行器服务来发送电子邮件。如果我在外部执行程序上调用关闭,它正在等待内部执行程序服务关闭,这会极大地影响响应时间。 private final ExecutorSer
我有两个 ExecutorService 实例:一个有 4 个线程,另一个有 20 个线程。我希望单击按钮后,服务 1 就会停止并等待服务 2 结束。之后,服务1继续运行。 我尝试使用 wait 和
我目前有一个 ExecutorService,我想要以下内容: 不应接受任何新任务。 当前任务仍应继续执行。 应返回所有当前排队的任务。 我面临的问题是 shutdown() 不会返回任何未执行的已提
/** * Blocks until all tasks have completed execution after a shutdown * request, or the timeout o
我在线程 A 上创建 ExecutorService,然后线程 B 在 ExecutorService 上调用 shutdown() 和 awaitTermination()。 假设在线程B创建之前所
为了提高请求的响应时间,我打算使用 executorService 并将工作分配给多个线程,以减少请求的响应时间。 但是在阅读文章和博客后,为每个请求创建新的线程池也会影响性能。 闲置方法是什么,-1
我正在学习使用 ExectorService 来汇集 threads 并发送任务。我下面有一个简单的程序 import java.util.concurrent.ExecutorService; im
这是我为暴露我的问题所做的一个简化示例。我有任务doSomeWork()我使用 ExecutorService(一次最多 4 个线程)以多线程方式处理。但是,如果任何线程/任务产生异常,我想: 停止处
我的类路径中有 Guava ,想使用 ListenableFuture s,但目前我不知道如何提交ListenableFuture s 还是目前只能在调用线程中没有执行程序的情况下使用它们?我读过 r
我正在学习 ExecutorService 和 Callables,但收到来自 intelij 的警告,说我正在为此行进行未经检查的分配: Future> future = executorServi
我正在编写一个 Java Fractal Explorer,分形计算是多线程完成的。以前,我只是创建了一堆线程(与系统有处理器内核一样多)并将它们保存在一个数组中,但这会导致一些问题并且不是很优雅,现
我想加入两个在 ExecutorService 中执行的线程。 public class CURD { public static ExecutorService executorService
我有一个工作单元列表,我想并行处理它们。每个单元工作 8-15 秒,完全计算时间,没有 I/O 阻塞。我想要实现的是拥有一个 ExecutorService那: 当没有工作要做时,实例化的线程为零 如
我想同时向最多 10 个用户发送 ping,并在 ping 完成后用结果更新用户对象。 为了做到这一点,我尝试使用 ExecutorService . 我从这样的代码开始: private void
我有一个在 ForkJoinPool 线程池中执行的递归批量任务。 public class SomeTask extends RecursiveAction { @Override
我有一个要遍历的列表,并且对于列表中的每个值都将调用一个方法。现在我已经将相关方法放在一个线程中,并使用执行器服务来并行处理这些方法。但是,对于列表中的每个值,该方法最终会由于某种原因被调用两次。 E
这个问题已经有答案了: How to wait for all threads to finish, using ExecutorService? (27 个回答) 已关闭 4 年前。 我正在尝试使用
我有一个基于ExecutorService线程流量调节的问题:我想 .submit() 多个线程来执行,我希望一些线程等待,直到特定的先前线程完成执行。 。 到目前为止,我知道一种通过使用 Count
我想知道这段代码是否正确。当我在构造对象本身时将可运行对象提交给执行器服务时,这不会导致问题吗? public class A implements Runnable { public
我是一名优秀的程序员,十分优秀!