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.
-
1No need for `synchronization` here probably. once the non-gui thread is finished, callback the function should mark that red to green, but make sure that function is called by event-dispatcher – Sep 20 '20 at 14:48
-
[`Platform.runLater(...)`](https://docs.oracle.com/javase/8/javafx/api/javafx/application/Platform.html#runLater-java.lang.Runnable-)? – Turing85 Sep 20 '20 at 14:48
-
You can find your answer here: https://stackoverflow.com/questions/14221617/waiting-for-thread-while-updating-swing – Mihai Pasca Sep 20 '20 at 14:51
-
@MihaiPasca the answer you provided a link to relates to _Swing_ while the question states that JavaFX is being used. Am I missing something? – Abra Sep 20 '20 at 15:15
-
Perhaps this Web page will help? [Concurrency in JavaFX](https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm) – Abra Sep 20 '20 at 15:18
2 Answers
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.

- 19,142
- 7
- 29
- 41
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();
}
}
}

- 30,962
- 25
- 85
- 135

- 11
- 3