英文:
Non-blocking signaling between threads
问题
我有一个JavaFX应用,在启动时运行两个线程。一个是UI线程,不能被阻塞。另一个是准备一个大表格的线程(大约需要20秒)。我想在第二个线程完成时通知UI线程,这样它就可以将一个矩形的颜色从红色更改为绿色。我尝试过使用synchronized关键字的解决方案,但它们都导致了UI线程被阻塞。
英文:
I have a JavaFX app that runs two threads at startup. One is the UI thread that must not be blocked. The other is a thread that prepares a large table (it takes about 20 seconds). I want to signal the UI thread when the second thread is done, so it can change the color of a rectangle from red to green. I have tried solutions using the synchronized keyword, but they all caused the UI thread to be blocked.
答案1
得分: 1
我使用了以下资源来获取下面的代码。
下面的应用程序简单地显示一个红色矩形,经过五秒钟后会变成绿色。在代码之后进行解释。
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class JfxTask0 extends Application {
private Task<Void> task;
@Override
public void init() throws Exception {
task = new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
Thread.sleep(5000L);
}
catch (InterruptedException xInterrupted) {
if (isCancelled()) {
System.out.println("CANCELLED!");
}
}
return null;
}
};
}
@Override
public void start(Stage primaryStage) throws Exception {
Rectangle rect = new Rectangle(25.0d, 25.0d, 50.0d, 50.0d);
rect.setFill(Color.RED);
task.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> workerStateProperty,
Worker.State oldValue,
Worker.State newValue) {
if (newValue == Worker.State.SUCCEEDED) {
rect.setFill(Color.GREEN);
}
}
});
new Thread(task).start();
Group root = new Group();
ObservableList<Node> children = root.getChildren();
children.add(rect);
Scene scene = new Scene(root, 100.0D, 100.0D);
primaryStage.setScene(scene);
primaryStage.setTitle("Task");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
方法init()
在类javafx.application.Application
中声明。它在方法start()
之前执行,正如其名称所示,用于初始化JavaFX应用程序。在这个方法中,我创建了后台任务。后台任务只是简单地睡眠了五秒钟。
在方法start()
中,我创建了红色矩形,然后启动了后台任务,但在启动任务之前,我为任务的一个属性注册了一个监听器。一旦任务完成,该属性将被设置为特定的值。
任务启动后,我构建了剩余的GUI并显示它。
一旦任务终止,监听器就会被调用,它将矩形的颜色设置为绿色。
英文:
I used the following resources to obtain the below code.
The below app simply displays a red rectangle which, after five seconds, turns to green. Explanations after the code.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class JfxTask0 extends Application {
private Task<Void> task;
@Override
public void init() throws Exception {
task = new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
Thread.sleep(5000L);
}
catch (InterruptedException xInterrupted) {
if (isCancelled()) {
System.out.println("CANCELLED!");
}
}
return null;
}
};
}
@Override
public void start(Stage primaryStage) throws Exception {
Rectangle rect = new Rectangle(25.0d, 25.0d, 50.0d, 50.0d);
rect.setFill(Color.RED);
task.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> workerStateProperty,
Worker.State oldValue,
Worker.State newValue) {
if (newValue == Worker.State.SUCCEEDED) {
rect.setFill(Color.GREEN);
}
}
});
new Thread(task).start();
Group root = new Group();
ObservableList<Node> children = root.getChildren();
children.add(rect);
Scene scene = new Scene(root, 100.0D, 100.0D);
primaryStage.setScene(scene);
primaryStage.setTitle("Task");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Method init()
is declared in class javafx.application.Application
. It is executed before method start()
and, as its name suggests, is used to initialize the JavaFX application. In this method I create the background task. The background task merely sleeps for five seconds.
In method start()
I create the red rectangle and then launch the background task but before launching the task, I register a listener with one of the task's properties. This property will be set to a particular value once the task completes.
After the task is launched, I build the rest of the GUI and display it.
Once the task terminates, then listener is invoked and it sets the rectangle color to green.
答案2
得分: 0
你可以为这个问题使用一个处理程序。
这里有一个示例。
在你的主活动中添加以下内容并创建处理程序。
Handler h = new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case 1:
// 在完成时执行的操作
break;
default:
break;
}
}
};
MyThread thread = new MyThread(new Messenger(h));
thread.start();
现在在你的线程文件中添加以下内容。
public class MyThread extends Thread {
Messenger m;
public MyThread(Messenger m){
this.m = m;
}
@Override
public void run(){
super.run();
// 你的代码
// 当任务完成时
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "";
try{
m.send(msg);
} catch(IOException e){
e.printStackTrace();
}
}
}
英文:
You can use a handler for this problem.
there is example
Add this in your main activity and create handler.
Handler h = new Handler(){
@Override public void handleMessage(Message msg){
switch(msg.what){
case 1:
// what you want when complete
break;
default:
break;
}
}
}
MyThread thread = new MyThread(new Messenger(h));
thread.start();
Now add this in your thread file.
public class MyThread{
Messenger m;
public MyThread(Messenger m){
this.m = m;
}
public void run(){
super.run();
// your codes
//
//when your task complete
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "";
try{
m.send(msg);
}catch(IOException e){
e.printStackTrace();
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论