JavaFX使线程等待和线程保存gui更新
所以我有这样的想法:JavaFX使线程等待和线程保存gui更新,java,multithreading,javafx,Java,Multithreading,Javafx,所以我有这样的想法: 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);
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()); });
}
}
公共类测试{
最终进度条=新进度条(0.0);
最终结果;
最终工人工作=新工人();
//GUI场景变化发生在这里
新线程(()->{
结果=工作剂量(此.bar);
}).start();
}
公社工人{
公共内部剂量测量(ProgressBar){
对于(inti=1;i{bar.setProgress(i/100000.0);});
返回51;
}
}
一切都很顺利,直到我不得不等待其他事情完成,然后才能继续运行,所以我对它进行了如下更改:
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()); });
}
}
公共类测试{
最终进度条=新进度条(0.0);
TextArea=新建TextArea();
int结果;
最终工人工作=新工人();
最终工人工作2=新工人2();
最终倒计时闩锁1=新倒计时闩锁(1);
//GUI场景变化发生在这里
新线程(()->{
结果=工作剂量(此.bar);
锁1.倒计时();
}).start();
锁1.等待();
新线程(()->{
工作2.剂量测量(结果、面积);
}).start();
}
公社工人{
公共内部剂量测量(ProgressBar){
对于(inti=1;i{bar.setProgress(i/100000.0);});
返回51;
}
}
公共班工人2{
ArrayList=新建ArrayList();
公共整数doSomething(整数索引,文本区域){
Platform.runLater(()->{area.append(list.get(index));});
}
}
后来我做了这样的事情:
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()); });
}
}
公共类测试{
最终进度条=新进度条(0.0);
TextArea=新建TextArea();
int结果;
最终工人工作=新工人();
最终工2工2=新工2();
最终工3工3=新工3();
最终倒计时闩锁1=新倒计时闩锁(1);
final CountDownLatch latch2=新的CountDownLatch(Map.keySet().size());
//这已经有了价值
//它实际上不是地图中的文件数组列表,但以这种方式显示它更容易
地图类型;
//GUI场景变化发生在这里
新线程(()->{
结果=工作剂量(此.bar);
锁1.倒计时();
}).start();
锁1.等待();
新线程(()->{
工作2.剂量测量(结果、面积);
}).start();
//即使我不在这里使用它,我也需要一个键集上的每个键
mapTypes.keySet().forEach((字符串s)->{
新线程(()->{
//在这里,我实际加载带有反射的类
工作3.剂量测量(mapTypes.get,面积);
锁2.倒计时();
}).start();
}
锁2.等待();
系统输出打印项次(“完成”);
}
公社工人{
公共内部剂量测量(ProgressBar){
对于(inti=1;i{bar.setProgress(i/100000.0);});
返回51;
}
}
公共班工人2{
ArrayList=新建ArrayList();
公共整数doSomething(整数索引,文本区域){
Platform.runLater(()->{area.append(list.get(index));});
}
}
公营工人3{
公共int doSomething(Arraylist文件、TextArea){
用于(文件f:文件)
Platform.runLater(()->{area.append(f.getName());});
}
}
现在,我的gui在切换场景时开始滞后,这意味着整个thread1自行处理,然后gui加载了所有内容。经过研究,我认为这是因为主线程正在处理runLater“请求”和等待()主线程必须等待第一个次线程进入倒计时()
我的问题是,如何管理主线程在第一个后台线程完成之前没有启动第二个后台线程?附加问题:更新GUI而不是Plattform.runlater()的更有效的方法是什么
注意:我也看过,但它没有完全解决我的问题,因为我不需要排队线程。我更需要知道如何使主线程等待子线程完成,然后再继续。但是,主线程不能完全处于非活动状态,而是管理传入的更新请求 先谢谢你 使用的技术: -NetBeans
-JavaFX(无FXML-代码中设计的所有内容)
-CSS
-Java(显然)
-Windows10Pro 代码的(主要)问题是在JavaFX应用程序线程上调用
latch.await()
,这是一种阻塞方法。由于JavaFX应用程序线程负责更新UI,因此在latch.await()
发布之前,无法重新绘制UI
你的问题的基本前提是错误的:你永远不想让UI线程暂停,因为它总是使UI没有响应并阻止任何更新。相反,你应该考虑“执行一个工作单元”在后台,可能会随着UI的进行而进行更新,然后根据后台工作的完成做一些事情
代码的另一个潜在问题是,您正在通过Platform.runLater()
向FX应用程序线程提交大量的Runnable
。您可能需要限制这些线程,以便它们不会“泛滥”FX应用程序线程
您可以使用解决所有这些问题。Task
类是Runnable
的一个实现,它的call()
方法是从run()
方法调用的。它有各种updateXXX
方法,包括updateProgress()
,它更新FX应用程序线程上的各种属性,并限制这些调用,以便调度的调用不会超过FX应用程序线程所能处理的。最后,它具有回调方法,例如setOnSucceeded()
,在后台工作完成时在FX应用程序线程上调用(或者,通常是