How do I wait for a SwingWorker's doInBackground() method? - java

Say I have the following code:
import java.lang.InterruptedException;
import javax.swing.SwingWorker;
public class Test
{
private JDialog window;
public Test
{
// instantiate window
}
private class Task extends SwingWorker<Void, Void>
{
public Void doInBackground()
{
try { Thread.currentThread().sleep(5000); }
catch(InterruptedException e) {}
return null;
}
}
public void doTask()
{
Task task = new Task();
task.execute();
}
protected void process()
{
// update various GUI components here
}
public static void main(String args[])
{
Test t = new Test();
t.doTask();
System.out.println("done");
}
}
I need to wait until t.doTask() is done before printing out 'done', but I'm not sure exactly how. I know I should probably use join() here, but I need a thread to call it on, and I don't know how to get doInBackground()'s thread from where I need to call join(). Thanks for any help.
EDIT: Thanks for the responses. Unfortunately, get() and the like don't quite solve the problem. In my actual code, the SwingWorker also has an overridden process() function that updates a GUI window while the background thread is running. get() does stop 'done' from being printed till after doInBackground, but then the GUI doesn't update. I updated my sample code to reflect this, although now of course it won't compile.
Is there a way to get 'done' to print only once doInBackground is finished? Are the GUI update code and the 'done' statement on the same thread? Do I need to make a new thread?

Typically anything that needs to be done after a SwingWorker completes its background work is done by overriding the done() method in it. This method is called on the Swing event thread after completion, allowing you to update the GUI or print something out or whatever. If you really do need to block until it completes, you can call get().
NB. Calling get() within the done() method will return with your result immediately, so you don't have to worry about that blocking any UI work.

Calling get() will cause the SwingWorker to block.
From the Javadocs:
T get()
Waits if necessary for the computation to complete,
and then retrieves its result.
Your code will then look like:
public static void main(String args[])
{
Test t = new Test();
t.doTask();
t.get(); // Will block
System.out.println("done");
}

You can override the done() method, which is called when the doInBackground() is complete. The done() method is called on EDT. So something like:
#Override
protected void done() {
try {
super.get();
System.out.println("done");
//can call other gui update code here
} catch (Throwable t) {
//do something with the exception
}
}
Calling the get() method inside the done helps get back any exceptions that were thrown during the doInBackground, so I highly recommend it. SwingWorker uses Callable and Future internally to manage the background thread, which you might want to read up on instead of trying the join/yield approach.

In general, you must hold onto the SwingWorker until it finishes, which you can test by calling isDone() on it. Otherwise just call get() which makes it wait.

Related

Force method to finish before continuing

I'm working on some sensitive LWJGL code and need to make sure that I create my display, and therefore GL context before executing any other code.
To give a clear example of my current predicament, take the following:
public static void main(String[] args) {
GLDisplay display = new GLDisplay();
display.start();
GLShader shader = new StaticShader();
}
The beginning of my GL creation happens in display.start(), where a separate thread is created, and within the separate thread, my Display is created.
Except this is where the problem lies, I have it in a separate thread. So then my program goes on and starts prematurely executing the new StaticShader() which calls even more GL code, breaking the program. (Can't execute before display is created).
What I'm trying to do, is achieve two threads simultaneously which I already have, but make sure that start() method is called completely before anything else is.
Here is how the start method works:
public synchronized void start() {
Threader.createThread(this, "GLDisplay");
}
#Override // public class GLDisplay extends Runnable
public void run() {
// GL code goes here.
}
And here is Threader:
public static void createThread(Runnable behaviour, String name) {
new Thread(behaviour, name + behaviour.hashCode()).start();
}
Now you may notice the synchronized keyword in the start method, well thats just one attempt I've had to no avail. I've also tried the following (which I actually grabbed from another StackOverflow answer):
#Override
public void run() {
synchronized(this) {
// GL code
}
}
I've checked other StackOverflow answers but either don't understand them or don't help me in my case. With the first code block I give in the main method, that is how I want my code to look to the person using it. I'm trying to put the thread-creation inside GlDisplay to hide it.
Any ideas?
Edit:
I can't simply wait for GLDisplay to close either (with Thread.join()) because there lies a while-loop that updates the display for the entirety of the program.
This is the entire reason I multi-threaded it. To allow this forever-ending loop to run while I do other things in the program. By closing the thread, I close the loop, cleanup the display and free the GL context from memory, once again making the shader code fail for lack of an existing context.
You can use java.util.concurrent.CountDownLatch to achieve it which aids in making a thread(s) wait till the operations on other threads is complete. Please see the reference on on what and how to use it.
Example:
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(1);
// pass the CountDownLatch into display
GLDisplay display = new GLDisplay(cdl);
display.start();
// wait for the latch to have been counted down in the disp thread
try
{
cdl.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
GLShader shader = new StaticShader();
}
In your GLDisplay thread, call the countDown method of CountDownLatch
I might be misunderstanding something, but try the following:
public static void createThread(Runnable behaviour, String name) {
Thread t = new Thread(behaviour, name + behaviour.hashCode()).start();
t.join();
}
By calling join() the program should wait for the thread to complete.
Well I remember now that I can't have GL code against two separate threads anyway, but thats besides the point.
I don't actually need to use any thread-lock classes or anything, but rather can just do something as simple as this:
private Boolean threadLock = true;
public void start() {
Threader.createThread(this, "GLDisplay");
while (true) {
synchronized(threadLock) {
if (!threadLock) break;
}
}
}
#Runnable
public void run() {
// Do GL code.
synchronized(threadLock) { threadLock = false; }
// Do the rest of whatever I'm doing.
}
When the threadlock is reached in the second thread and is released, the first thread continues doing it's activity. It's that simple!

How return a result of my method executed in thread?

I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}

Easy way to call method in new thread

I'm writing small app and now I discovered a problem.
I need to call one(later maybe two) method (this method loads something and returns the result) without lagging in window of app.
I found classes like Executor or Callable, but I don't understand how to work with those ones.
Can you please post any solution, which helps me?
Thanks for all advices.
Edit: The method MUST return the result. This result depends on parametrs.
Something like this:
public static HtmlPage getPage(String page) throws FailingHttpStatusCodeException, MalformedURLException, IOException {
return webClient.getPage(page);
}
This method works about 8-10 seconds. After execute this method, thread can be stopped. But I need to call the methods every 2 minutes.
Edit: I edited code with this:
public static HtmlPage getPage(final String page) throws FailingHttpStatusCodeException, MalformedURLException, IOException {
Thread thread = new Thread() {
public void run() {
try {
loadedPage = webClient.getPage(page);
} catch (FailingHttpStatusCodeException | IOException e) {
e.printStackTrace();
}
}
};
thread.start();
try {
return loadedPage;
} catch (Exception e) {
return null;
}
}
With this code I get error again (even if I put return null out of catch block).
Since Java 8 you can use shorter form:
new Thread(() -> {
// Insert some method call here.
}).start();
Update:
Also, you could use method reference:
class Example {
public static void main(String[] args){
new Thread(Example::someMethod).start();
}
public static void someMethod(){
// Insert some code here
}
}
You are able to use it when your argument list is the same as in required #FunctionalInterface, e.g. Runnable or Callable.
Update 2:
I strongly recommend utilizing java.util.concurrent.Executors#newSingleThreadExecutor() for executing fire-and-forget tasks.
Example:
Executors
.newSingleThreadExecutor()
.submit(Example::someMethod);
See more: Platform.runLater and Task in JavaFX, Method References.
Firstly, I would recommend looking at the Java Thread Documentation.
With a Thread, you can pass in an interface type called a Runnable. The documentation can be found here. A runnable is an object that has a run method. When you start a thread, it will call whatever code is in the run method of this runnable object. For example:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// Insert some method call here.
}
});
Now, what this means is when you call t.start(), it will run whatever code you need it to without lagging the main thread. This is called an Asynchronous method call, which means that it runs in parallel to any other thread you have open, like your main thread. :)
In Java 8 if there is no parameters required you can use:
new Thread(MyClass::doWork).start();
Or in case of parameters:
new Thread(() -> doWork(someParam))

Wait for thread to finish in Java

I have some code which executes a download in a separate thread, created so that the JFrame GUI will continue to update during the download. But, the purpose is completely defeated when I use Thread.join(), as it causes the GUI to stop updating. I need a way to wait for the thread to finish and still update the GUI.
You can have the task that does the download also fire an event to the GUI.
For example:
Runnable task = new Runnable() {
public void run() {
// do your download
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// call some method to tell the GUI that the download finished.
}
});
}
};
and then to run it, either use an Executor (preferred method) or a raw thread:
executor.execute(task);
or
new Thread(task).start();
As pointed out in the comments, you'd generally use a SwingWorker to do this kind of thing but you can also do the manual approach outlined above.
SwingWorker provides a doInBackground method where you would stick your download logic in, a done method where you would stick in code to notify the GUI that the download finished and a get method to get the result of doInBackground (if there was one).
E.g.,
class Downloader extends SwingWorker<Object, Object> {
#Override
public Object doInBackground() {
return doDownload();
}
#Override
protected void done() {
try {
frame.downloadDone(get());
} catch (Exception ignore) {
}
}
}
(new Downloader()).execute();

java swing addTaskListener

I am new to java and have a swing task question.
Can I add a listener to a currently running task? For instance if something happens in doInBackGround I want to add a listener for finished and display a dialog. I have tried but the compiler doesnt like me. :)
Something like.
private class MyTask extends Task<Void, Void>{
#Override
public void doInBackground(){
if(foo == foo){
this.addTaskListener(new TaskListener() {
public void taskFinsished(){}...
});
}
}
}
Thanks
Task is not a listener-oriented component. You need to override one or more of it's methods to get the results. All of these methods will execute on the EDT.
cancelled() - The cancel() method was called to terminate the task.
succeeded(T result) - The Task completed, and result holds the return value from doInBackground().
interrupted(InterruptedException e) - interrupt was called on the Thread executing the Task.
failed(Throwable cause) - The doInBackground threw an exception.
finished() - The Task has finished (in some fashion). Think of this as the functional equivalent of finally for Tasks.

Categories