I have been doing some research on this but I am still VERY confused to say the least.
Can anyone give me a concrete example of when to use Task and when to use Platform.runLater(Runnable);? What exactly is the difference? Is there a golden rule to when to use any of these?
Also correct me if I'm wrong but aren't these two "Objects" a way of creating another thread inside the main thread in a GUI (used for updating the GUI)?
Use Platform.runLater(...) for quick and simple operations and Task for complex and big operations .
Use case for Platform.runLater(...)
Use case for Task: Task Example in Ensemble App
Example: Why Can't we use Platform.runLater(...) for long calculations (Taken from below reference).
Problem: Background thread which just counts from 0 to 1 million and update progress bar in UI.
Code using Platform.runLater(...):
final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
#Override public void run() {
for (int i = 1; i <= 1000000; i++) {
final int counter = i;
Platform.runLater(new Runnable() {
#Override public void run() {
bar.setProgress(counter / 1000000.0);
}
});
}
}).start();
This is a hideous hunk of code, a crime against nature (and
programming in general). First, you’ll lose brain cells just looking
at this double nesting of Runnables. Second, it is going to swamp the
event queue with little Runnables — a million of them in fact.
Clearly, we needed some API to make it easier to write background
workers which then communicate back with the UI.
Code using Task :
Task task = new Task<Void>() {
#Override public Void call() {
static final int max = 1000000;
for (int i = 1; i <= max; i++) {
updateProgress(i, max);
}
return null;
}
};
ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
it suffers from none of the flaws exhibited in the previous code
Reference :
Worker Threading in JavaFX 2.0
Platform.runLater: If you need to update a GUI component from a non-GUI thread, you can use that to put your update in a queue and it will be handled by the GUI thread as soon as possible.
Task implements the Worker interface which is used when you need to run a long task outside the GUI thread (to avoid freezing your application) but still need to interact with the GUI at some stage.
If you are familiar with Swing, the former is equivalent to SwingUtilities.invokeLater and the latter to the concept of SwingWorker.
The javadoc of Task gives many examples which should clarify how they can be used. You can also refer to the tutorial on concurrency.
It can now be changed to lambda version
#Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(() -> {
try {
//an event with a button maybe
System.out.println("button is clicked");
} catch (IOException | COSVisitorException ex) {
Exceptions.printStackTrace(ex);
}
});
}
One reason to use an explicite Platform.runLater() could be that you bound a property in the ui to a service (result) property. So if you update the bound service property, you have to do this via runLater():
In UI thread also known as the JavaFX Application thread:
...
listView.itemsProperty().bind(myListService.resultProperty());
...
in Service implementation (background worker):
...
Platform.runLater(() -> result.add("Element " + finalI));
...
Related
I have the following issue, or want to do, that I have n running SwingWorkers, the number can vary between 1 and 10. I start them from a main thread, and create them in n numbers, then let them run. After all n SwingWorkers are done, I want to do another task, which basically uses information, the SwingWorkers processed and join them all in the main thread to do something with it. But for this task to begin, all n SwingWorkers need to be finished/done and all n SwingWorkers need to be finished successfully.
What would be the best way to do this? Is there a mechanism in Java already, which does something like this, like a ThreadManager, where you can put multiple SwingWorkers into, and then it fires a doneAll() or something like that to the main thread?
The main thread does other things in the meantime, and cant just wait for the n SwingWorkers to finish. I need an "all done" fire event somehow.
I though of creating another thread in the main thread, which runs a while loop (untillAllSWFfinished), with a wait 500ms in the loop to check, but that seems a bit dirty to me.
Is there a more elegant way to achieve this?
If you know how many workers you're kicking off, you can use a CountdownLatch. If you don't know how many works are being kicked off, you can use a Phaser.
Example:
//using a button as a basic UI component to do work.
JButton button = new JButton(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
Runnable control = new Runnable() {
#Override
public void run() {
//assuming we know we're going to do 20 bits of isolated work.
final CountDownLatch latch = new CountDownLatch(20);
for (int i = 0; i < 20; i++) {
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
//do your work
return null;
}
#Override
public void done() {
latch.countDown();
}
};
worker.run()
}
try {
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
//so your next bit of work.
}
};
SwingUtilities.invokeLater(control);
}
});
Have the following, rather trivial intention in an JFX application: When a key is pressed on the keyboard and thus a handle(event ev) method is called, I want that something happens in a different, otherwise unused thread.
So far I found to have three options:
Either creating the new thread directly in the handle:
public void handle(KeyEvent ke)
{
new Thread(() -> {
// THE CODE
}).start();
}
}
Or I launch a different thread at programm start looking about like this:
public void run()
{
while(true)
{
if (triggered)
{
// THE CODE
}
}
}
and then in the handle() method, I just set the "triggered" field to true.
The third method would be to create as many instances of a class extending "Thread" as needed to be executed in parallel and use their start() function in the handle().
Well, from what I see, the former method has a significant overhead due to thread creation.
The second method is pointlessly requiring CPU resources 99.9% of the time.
That can only be weakened by adding a sleep() to the loop.
And the third method appears to be quite similar to the first as most resources are allocated when called start(), or am I wrong?
That method also has the downside to have to keep several instances in memmory because I can not preddict how many will be called in parallel.
What solution would you suggest?
Are there other possibilities?
Huge thanks in advance!
I suggest adding the task to an ExecutorService This works as a background thread pool and is idle when not used. The threads in it are reused however to improve efficiency. You can use a cached thread pool if you don't know how many threads at once you will need.
static final ExecutorService executor = Executors.newCachedThreadPool();
public void handle(KeyEvent ke)
{
executor.execute(() -> {
// THE CODE
});
}
or
public void handle(KeyEvent ke)
{
executor.execute(this::task1);
}
void task1()
{
// THE CODE
}
You can use a ThreadPoolExecutor, so you can avoid:
repeatly creating new thread
unnecessarily check triggered status
Like this:
ExecutorService executor = executors.newcachedthreadpool();
public void handle(KeyEvent ke)
{
Runnable runnable = new Runnable() {
void run() {
// code
}
}
executor.execute(runnable);
}
You could either use a JavaFX Service (https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Service.html) or create a Task (https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html) that you submit manually with a new Thread or using an Executor, for example from Executors.newCachedThreadPool().
The alternatives are covered quite well in https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm.
Based on what you have written I would probably go for the Service, but both alternatives should work.
I have a project that takes time to load everything so I create a splash screen that tells the user through a progressbar how much time it will take to fully load and show the UI, but I'm facing a problem.
When I create my splash, this shows up correctly but then I create and initialize the Principal frame and everything freeze until this has fully load.
So, I try to load my Principal frame in a thread using SwingWorker (and it works) but after unknown NullPointerExceptions and reading a lot I found that this is a terrible idea because I am not creating my UI in the EDT, so here I am stuck.
I know that I must do Swing Calls in the Event Dispatch Thread (EDT) and non-swing heavy work in SwingWorkers but initialize the Swing Components of my Principal Frame are a heavy work too so, what should I do?
I have read some question here, specially this, and I think I get it but I have doubts. Taking that example:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new SplashScreen();
}
});
// Code to start system (nothing that touches the GUI)
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new MainFrame();
}
});
//.. etc
And reading this site that says:
The Swing framework manages component drawing, updates, and event handlers on the EDT.
Is creating a new component a Swing Call? If it is, What should I do if new MainFrame() will take some time because the project has a lot of components to initialize?
How do I tell the Splash something like "Program loaded 50%"?
What does a Swing Call means and how can I do a correct use of invokeLater and SwingWorker? Maybe the solution is too obvious or have already an answer, but I can't see it and I apologize if this is the case.
Thanks!
You're on a right track. But don't use invokeAndWait (if you have to only) - use invokeLater:
invokeAndWait
Causes doRun.run() to be executed synchronously on the AWT event dispatching thread.
invokeLater
Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread.
Consider that block wrapped doLater is run on EDT thread and code wrapped in doOutside is invoked in another thread (and that's why you don't block the UI):
EDIT:
As pointed out in the comments I add the explanations for the concepts I'll use.
doLater {
// here goes the code
}
is a concept for:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// here goes the code
}
});
And
doOutside {
// here goes the code
}
is a concept for:
new Thread(new Runnable() {
#Override
public void run() {
// here goes the code
}
}).start();
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle heavy operation
final int result = 1;
doLater {
m.setResult(result);
}
}
}
Conclusion: everything that touches Swing in some way must be run on EDT.
If you want to update percentages:
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle progress
for(int i = 0; i < someSize; ++i) {
final int progress = i;
doLater {
m.getProgressBar().setProgress(progress);
}
}
}
}
I hope you understand the concept now. The SwingWorker just do exectly something as doOutside === doInBackground & doLater === done/progress
Btw. The code above is a real code: lookup Griffon framework in Groovy.
I have been struggling to accomplish a GUI driven task that is initiated in a thread that takes a while to compute and is also accomplished over the JNI using C++ native code. When the computationally intensive task is run, the synchronization is lost, otherwise, synchronization is fine.
Can someone help with an implementation structure where synchronization of the time is not lost? I have a hunch it is because my use of JNI.
The structure of the my problem is below:
1) A button (animate) is selected and triggers an event for a GUI listener
2) GUI recognized that the button was pressed and starts a thread below:
3) Once button is pressed again, the thread closes.
private class Animator implements Runnable
{
public void start()
{
if (thread == null)
{
thread = new Thread(this, "Animator");
thread.start();
}
}
public void run()
{
while (animate.isSelected())
{
updateAnimations();
}
resetAnimations();
thread = null;
}
public void updateAnimations()
{
double time = scene.getTime(); // A singleton class and scene time
time += 10;
scene.update(time); // the scene updates its parameters to time and redraws the GUI. One of the computations is done over the JNI and takes too long and synchronization is lost (i.e. time = [10 40 80 ...])
}
Thread thread;
}
I'm making a chess program for a project. I'm trying to add a move history box to the side of the board. The move history works fine, and the data is properly sent to the text area, but the text inside the JTextArea disappears while the AI is thinking about his move.
public void aiMove(){
if (!playing){ return; }
paintImmediately(0,0,totalX,totalY);
ai = eve.getMove(chess,wtm,aiOut); //text disappears here
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
writeMove(ai); //updates move history, text reappears here
playing = stillPlaying();
repaint();
}
private void writeMove(Move move){
char c = "abcdefgh".charAt(7-move.fromY);
char h ="abcdefgh".charAt(7-move.toY);
String s = Character.toString(c)+(move.fromX+1)+" - "+Character.toString(h)+(move.toX+1)+" ";
if (!wtm){
String q = chess.getFullMove()+". "+s+" ";
moves.setText(moves.getText()+q);
}
else {
moves.setText(moves.getText()+s+"\n");
}
}
Here's a print screen of what's happening.
http://s13.postimage.org/mh7hltfk7/JText_Area_disappear.png
SOLVED
Thanks to all replies. I changed aiMove() so it creates a thread. Here is what I did.
Attempt #3... swing is still so foreign to me. I didn't want to change writeMove to getMove or I would have to rewrite the human's turn slightly. Since the project is essentially done, I am trying to avoid as much work as possible :)
The GUI is entirely optional anyways, I was just doing it for fun, and to try and learn a bit of swing.
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}
It also fixed a problem I had before, in that if I were to hold down the 'a' key (force ai move), it would queue up many forced ai moves. Now that doesn't happen.
The problem is your AI thinking is CPU intensive/time consuming, thus it is considered a long running task. You should not do long running tasks on GUI Event Dispatch Thread as this will cause the UI to seem frozen and thus only show updates after the task has finished.
Fortunately there are 2 different approaches you could use:
Use a Swing Worker which as the tutorial states:
The SwingWorker subclass can define a method, done, which is
automatically invoked on the event dispatch thread when the background
task is finished.
SwingWorker implements java.util.concurrent.Future.
This interface allows the background task to provide a return value to
the other thread. Other methods in this interface allow cancellation
of the background task and discovering whether the background task has
finished or been cancelled.
The background task can provide
intermediate results by invoking SwingWorker.publish, causing
SwingWorker.process to be invoked from the event dispatch thread.
The background task can define bound properties. Changes to these
properties trigger events, causing event-handling methods to be
invoked on the event dispatch thread.
Alternatively create separate Thread for AI thinking and wrap setText call in SwingUtilities.invokeLater(...);
Thread t=new Thread(new Runnable() {
#Override
public void run() {
}
});
t.start();
UPDATE
After reading MadProgrammers comment (+1 to it) please remember to create/manipulate your GUI/Swing components on EDT via the SwingUtilities.invokeLater(..) block. You can read more on it here.
UPDATE 2:
That edit is defeating the point, the only call on EDT in SwingUtilitites block should be the setText or atleast only code that manipulates a Swing component i.e
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){ //originally initialized by constructor
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}