How to signal that multiple SwingWorkers are all done? - java

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);
}
});

Related

Java Swing GUI updating/changing from method - freezing in loop

basically, I have this code which was initially working with console i/o now I have to connect it to UI. It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.
I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.
This is the button on GUI class containing the method that needs to change this GUI.
public class GUI {
...
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.startTest(index, idUser);
}
});
}
This is the method startTest from another class which contains instance of Question class.
public int startTest() {
for (int i = 0; i < this.numberofQuestions; i++) {
Question qt = this.q[i];
qt.askQuestion(); <--- This needs to change Label in GUI
if(!qt.userAnswer()) <--- This needs to get string from TextField
decreaseScore(1);
}
return actScore();
}
askQuestion method:
public void askQuestion() {
System.out.println(getQuestion());
/* I've tried to change staticaly declared frame in GUI from there */
}
userAnswer method:
public boolean userAnswer() {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
if( Objects.equals(getAnswer(),userInput) ) {
System.out.println("Correct");
return true;
}
System.out.println("False");
return false;
}
Thanks for help.
You're correct in thinking that it related to threads.
When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.
As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.
A good way to implement it would be this:
public class TestWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
//This is where you execute the long running
//code
controller.startTest(index, idUser);
publish("Finish");
}
#Override
protected void process(List<String> chunks) {
//Called when the task has finished executing.
//This is where you can update your GUI when
//the task is complete or when you want to
//notify the user of a change.
}
}
Use TestWorker.execute() to start the worker.
This website provides a good example on how to use
the SwingWorker class.
As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:
Thread t = new Thread(){
#Override
public void run(){
// do stuff
}
};
t.start();
Or if you use Java 8+:
Thread t = new Thread(() -> {
// do stuff
});
t.start();

JTextArea text disappears

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();
}
}

Platform.runLater and Task in JavaFX

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));
...

SwingWorker to run class that creates threads. Java

I have "Creator" class that has anonymous inner runnable class that creates threads. I also have GUI class that creates GUI and on button press executes the "Creator" class. But then my GUI freezes until all threads created by "Creator" are completed. I found that SwingWorker could help me in this situation, but I fail to understand how to create one in this particular situation. And is there any other easy way to do that, than SwingWorker?
Here is the code for my Creator class:
public class Creator {
final ExecutorService es;
Collection<Future<?>> futures = new LinkedList<>();
public Creator() {
es = Executors.newFixedThreadPool(10);
}
public void runCreator() {
for (int i = 0; i < 100; i++) {
futures.add(es.submit(new Check(i)));
}
es.shutdown();
for (Future<?> future : futures) {
try {
future.get();
} catch (Exception ex) {
}
}
}
private class Check implements Runnable {
private int i;
private Check(int i) {
this.i = i;
}
#Override
public void run() {
System.out.println("Number: "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
}
The reason why your code is hanging until it completes, is because of the call to your Future's get method. This will wait until it has completed. Also, you probably do not want to shutdown your pool right after adding all of your threads. It would be better to just add a on close event and shut it down there.
Since all that you are doing is printing a number and sleeping, you do not need to wait for the Future to complete. Just remove the call to get and the delay should stop.
Yes, Swing worker is the way to go - there are enough examples on the web, but to summarize - put your thread-spawning and waiting code in doInBackground(), if you want to report interim progress, use publish()/process() and finally, get your data to the Swing EDT thread in done().
PS. irrelevant to the SwingWorker usage, you might want to consider using a completion service rather than waiting on all futures in order.

How to use MultiThreading in Android for an Event Handling Function (SensorListeners)

I have an event handling mechanism in my Android code to dump the sensor values in a file. Right now, I'm doing it in the main UI thread and hence the UI button responsiveness is very sluggish and I would like to speed it up.
How can I use multithreading on event handling functions? I'm trying to do it like this:
Create a global variable writeNow.
When the sensor value changes, set WriteNow = true
Create a thread in the class which looks like this:
Thread thread1 = new Thread()
{
public void run()
{
if(writeNow == true)
{
try
{
fos.write(s.getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
writeNow = false;
}
}
};
Thus, whenever writeNow is true, it will write to a File and then set WriteNow to false. However, I realize this is not the right approach, because the thread will execute once and then stop executing. When I tried a simple example with a while(true) and wait(), I found that the thread is interrupted millions of times.
So how do I enclose this event handling mechanism in a single thread, for speeding up a process?
Thanks!
You can try one of the following approaches:
It looks like you're trying to keep your writer thread running all the time; what you can do is spawn the thread only when you need it. Take a look at the example in the Android documentation for handling expensive operation in the UI thread.
Here is the example from that page:
public class MyActivity extends Activity {
[ . . . ]
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[ . . . ]
}
protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mResults = doSomethingExpensive();
mHandler.post(mUpdateResults);
}
};
t.start();
}
private void updateResultsInUi() {
// Back in the UI thread -- update our UI elements based on the data in mResults
[ . . . ]
}
}
Since it doesn't look like you're doing anything in the UI thread once you finish writing you don't really need to bother with a Handler. But you might want to use it to display a Toast once the file has been written to.
On the other hand, if you still want to have a thread running, you might have it sleep() and periodically wake up and check the status of writeNow.
Thread thread1 = new Thread()
{
public void run()
{
while(true)
{
if(writeNow == true)
{
try
{
fos.write(s.getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
writeNow = false;
}
try
{
Thread.sleep(100); //sleep for 100 ms
}
catch (InterruptedException e)
{
Log.d('', e.getMessage());
}
}
}
};
Note that this will quickly get complicated and you might lose the bytes you want to write if your thread is sleeping when new data comes in and when it wakes up, even newer data has been received and has overwritten the previous bytes. You'd need some sort of a queue to manage that.
I'm not sure what you were doing with the wait() but that should've also worked and is in fact, the approach for problems involving a consumer and producer. The idea is to have your thread synchronize and wait() on a shared object (like perhaps your queue of bytes); a second thread will call notify() on the shared object when there is data available to write and the writer thread will be woken up. The writer thread should then write and reloop. Take a look at this tutorial.
As for the interruption of your thread, your thread may be interrupted for a number of reasons which is why it is good practice (especially when using wait()) to ensure that the condition you checked before you called wait() is still valid because you could've been woken because of either a call to notify()/notifyAll() or because of an interruption.
Handler handler = null;
handler = new Handler();
//create another class for and make consrtuctor as u want. so that u can use that effectively.
//for example.
popupIndex = new IndexThread(handler,head, target,ltp,price,IndexNifty.this,columsView,call);
popupIndex.setColumnViewexit(columsView);
handler.postDelayed(popupIndex, 300);
//another class
public IntraThread(Handler handler,String script,int target,int ltp,int price,Intraday intraday,TextView columsView,String call){
super();
this.target = target;
this.ltp = ltp;
this.price = price;
this.intraday = intraday;
this.columsView = columsView;
this.script= script;
this.handler= handler;
this.call= call;
}
public void run(){
// write ur code here....
}

Categories

Resources