所以我有这样的东西:
public class test {
final ProgressBar bar = new ProgressBar(0.0);
final int result;
final worker work = new worker();
// GUI Scene change happens here
new Thread(() -> {
result = work.doSomething(this.bar);
}).start();
}
public class worker{
public int doSomething(ProgressBar bar){
for(int i = 1; i <= 1000000; i++)
Platform.runLater(() -> { bar.setProgress(i/100000.0); });
return 51;
}
}
一切都很好,直到我不得不等待其他事情完成,然后才能继续运行,所以我这样修改了它:
public class test {
final ProgressBar bar = new ProgressBar(0.0);
TextArea area = new TextArea();
int result;
final worker work = new worker();
final worker work2 = new worker2();
final CountDownLatch latch1 = new CountDownLatch(1);
// GUI Scene change happens here
new Thread(() -> {
result = work.doSomething(this.bar);
latch1.CountDown();
}).start();
latch1.await();
new Thread(() -> {
work2.doSomething(result, area);
}).start();
}
public class worker{
public int doSomething(ProgressBar bar){
for(int i = 1; i <= 1000000; i++)
Platform.runLater(() -> { bar.setProgress(i/100000.0); });
return 51;
}
}
public class worker2{
ArrayList<String> list = new ArrayList<>();
public int doSomething(int index, TextArea area){
Platform.runLater(() -> { area.append(list.get(index)); });
}
}
后来我做了这样的事情:
public class test {
final ProgressBar bar = new ProgressBar(0.0);
TextArea area = new TextArea();
int result;
final worker work = new worker();
final worker2 work2 = new worker2();
final worker3 work3 = new worker3();
final CountDownLatch latch1 = new CountDownLatch(1);
final CountDownLatch latch2 = new CountDownLatch(Map.keySet().size());
// This already has values
// it is not really a file array list in the map, but it is easier to show it this way
Map<String, ArrayList<File>> mapTypes;
// GUI Scene change happens here
new Thread(() -> {
result = work.doSomething(this.bar);
latch1.CountDown();
}).start();
latch1.await();
new Thread(() -> {
work2.doSomething(result, area);
}).start();
// Even thought I don't use it here I need a for each on the keyset
mapTypes.keySet().forEach((String s) -> {
new Thread(() -> {
// Here I actually load classes with a reflection
work3.doSomething(mapTypes.get(s), area);
latch2.CountDown();
}).start();
}
latch2.await();
System.out.println("Done");
}
public class worker{
public int doSomething(ProgressBar bar){
for(int i = 1; i <= 1000000; i++)
Platform.runLater(() -> { bar.setProgress(i/100000.0); });
return 51;
}
}
public class worker2{
ArrayList<String> list = new ArrayList<>();
public int doSomething(int index, TextArea area){
Platform.runLater(() -> { area.append(list.get(index)); });
}
}
public class worker3{
public int doSomething(Arraylist<File> files, TextArea area){
for (File f : files)
Platform.runLater(() -> { area.append(f.getName()); });
}
}
现在,我的gui在切换场景时开始滞后 - 这意味着 - 整个thread1自行处理,然后gui加载所有内容。经过一些研究,我认为发生这种情况是因为主线程正在处理runLater“请求”,并且由于wait(),主线程必须等到第一个辅助线程来到CountDown()。
我的问题是,在第一个线程完成之前,我如何管理主线程不启动第二个后台线程?额外的问题:什么是比Plattform.runlater()更有效的更新我的GUI的方法?
注意:
我也看过这个问题,但它没有完全解决我的问题,因为我不需要排队线程。我更需要知道如何让主线程等到子线程完成,然后才继续。但是,主线程不能完全处于非活动状态,而是管理传入的更新请求。
提前谢谢你
使用的技术:-NetBeans
-JavaFX(没有FXML-代码中设计的一切)
-CSS
-Java(显然)
-Windows 10 pro
代码的(主要)问题是您在 JavaFX 应用程序线程上调用 latch.await()
,这是一种阻塞方法。由于 JavaFX 应用程序线程负责更新 UI,因此在 latch.await()
发布之前,这可以防止 UI 被重新绘制。
您的问题的基本前提是错误的:您永远不想让UI线程暂停,因为它总是会使UI无响应并阻止任何更新。相反,您应该考虑在后台“执行一个工作单元”,可能会随着UI的进行进行更新,然后做一些事情来响应后台工作的完成。
代码的另一个潜在问题是,您通过< code>Platform.runLater()向FX应用程序线程提交了大量的< code>Runnable。您可能需要限制这些线程,使它们不会“淹没”FX应用程序线程。
您可以使用Task
API解决所有这些问题。Task
类是Runnable
的实现,其call()
方法是从run()
方法调用的。它有各种updateXXX
方法,包括updategres()
,它们更新FX Application线程上的各种属性,并限制这些调用,以便不超过FX Application线程可以处理的调度。最后,它有回调方法,例如setOn成功()
,当后台工作完成时(或者,通常,当任务更改其生命周期状态时)在FX Application Thread上调用。
(注意:我重命名了您的类,使它们符合推荐的命名约定。与大多数Java开发人员一样,我发现阅读不符合这些约定的代码非常困难。)
public class Test {
final ProgressBar bar = new ProgressBar(0.0);
TextArea area = new TextArea();
int result;
final Worker work = new Worker();
final Worker2 work2 = new Worker2();
// GUI Scene change happens here
work.setOnSucceeded(e -> work2.doSomething(work.getValue(), area));
bar.progressProperty().bind(work.progressProperty());
new Thread(work).start();
}
public class Worker extends Task<Integer> {
@Override
protected Integer call(){
for(int i = 1; i <= 1000000; i++)
updateProgress(i, 1000000);
return 51;
}
}
public class Worker2{
ArrayList<String> list = new ArrayList<>();
// this is now executed on the FX Application Thread: there is no need
// for Platform.runLater():
public int doSomething(int index, TextArea area){
area.append(list.get(index));
}
}
您的第二个示例稍微复杂一点,我不确定您是否需要额外的线程:您的< code>Worker3似乎做的唯一一件事就是在文本区域追加一行,这无论如何都必须在FX应用程序线程上完成。但是,如果您的实际应用程序需要为每个文件做后台工作,这就是它看起来的样子。我建议使用任务池,而不是手工创建这么多任务。这将类似于:
public class Test {
final ProgressBar bar = new ProgressBar(0.0);
TextArea area = new TextArea();
int result;
final Worker work = new Worker();
final Worker2 work2 = new Worker2();
final ExecutorService exec = Executors.newCachedThreadPool();
// This already has values
// it is not really a file array list in the map, but it is easier to show it this way
Map<String, ArrayList<File>> mapTypes;
// GUI Scene change happens here
work.setOnSucceeded(e -> {
work2.doSomething(work.getValue(), area);
Task<Void> processAllFiles = new Task<Void>() {
@Override
protected Void call() throws Exception {
final CountDownLatch latch2 = new CountDownLatch(Map.keySet().size());
mapTypes.keySet().forEach((String s) -> {
exec.submit(() -> {
work3.doSomething(mapTypes.get(s), area);
latch2.CountDown();
});
});
latch2.await();
return null ;
}
};
processAllFiles.setOnSucceeded(evt -> {
// executed on fx application thread:
System.out.println("Done");
});
});
bar.progressProperty().bind(work.progressProperty());
exec.submit(work);
}
我知道使用无线程异步有更多线程可用于服务输入(例如HTTP请求),但我不明白当异步操作完成并且需要一个线程来运行它们的延续时,这如何不可能导致线程饥饿。 假设我们只有3个线程 并且它们在需要线程的长时间运行的操作中被阻塞(例如在单独的db服务器上进行数据库查询) 使用async Wait,您可以 然而,在我看来,这可能会导致“正在进行”的异步操作过剩,如果太多的操作同时完成,那么就没有线程可以运行
按下按钮后,我的界面冻结。我使用线程,但我不知道为什么仍然挂起。任何帮助都将不胜感激。提前谢谢
问题内容: 我正在为我的ubuntu服务器(针对我的多客户端匿名聊天程序)实现一种简单的线程池机制,并且需要使我的工作线程进入睡眠状态,直到需要执行一项工作(以函数指针和参数的形式) 。 我当前的系统即将关闭。我(工人线程正在)问经理是否有工作可用,以及是否有5毫秒没有睡眠。如果存在,请将作业添加到工作队列中并运行该函数。糟糕的循环浪费。 什么我 喜欢 做的是做一个简单的事件性的系统。我正在考虑有
我在使用JavaFX和线程时遇到问题。基本上我有两个选择:使用或。据我所知,应用于简单/简短的任务,而应用于较长的任务。然而,我不能使用它们中的任何一个。 当我调用时,它必须在任务执行过程中弹出一个验证码对话框。在使用任务时,它忽略了我显示新对话框的请求。。。它不允许我创造一个新的舞台。 另一方面,当我使用,它允许我显示一个对话框,但是,程序的主窗口会冻结,直到显示弹出对话框。 我需要任何解决办法
我正在我的UI线程中调用一个方法。在这个方法中创建了一个新线程。我需要UI线程等待这个新线程完成,因为我需要这个线程的结果来继续UI线程中的方法。但我不想让UI在等待时冻结。有没有办法让UI线程在不忙的情况下等待?。
问题内容: 我有以下情况: 为了运行算法,我必须运行多个线程,并且每个线程都会在死之前设置一个实例变量x。问题是这些线程不会立即返回: 我应该使用等待通知吗?还是我应该嵌入一个while循环并检查是否终止? 感谢大家! 问题答案: 创建一些共享存储来保存每个线程的值,或者如果足够的话,只存储总和。使用a 等待线程终止。每个线程完成后都会调用,您的方法将使用该方法来等待它们。 编辑: 这是我建议的方