I am having some problems cancelling a swing worker. I am unsure after reading the documentation how to approach solving this
sw = new SwingWorker<Object, Void>()
{
Object o;
protected Object doInBackground() throws Exception
{
//do some long running task via a method call
}
}
Then in my cancel button handler i just want to call sw.cancel(true);
This doesnt seem to be working though. According to the documentation the swing worker needs to no how to cancel iteslf. But, if the method to run the swing worker is only being calld once then how do i account for this with thread.sleep(which is what i've read is one way of fixing)
Thanks
Swing will actually monitor your work with a Future. When you try to cancel the worker Swing will invoke future.cancel(true) (the true value will attempt to interrupt() the executing thread).
What this means is your work needs to respond to interruption. If the long running computations don't respond to interruption you will have to put in some checkpoints and respond accordingly
protected Object doInBackground() throws Exception
{
//do part 1 of long running task
if(Thread.currentThread().isInterrupted()){
//clean up and return
}
//do part 2 of long running task
if(Thread.currentThread().isInterrupted()){
//clean up and return
}
//etc..
}
Swing will simply notify the executing thread that it should cancel. It is your responsibility to actually enforce cancellation.
There's a pretty good article here: http://blogs.oracle.com/swinger/entry/swingworker_stop_that_train
In brief, calling cancel() sets the thread's 'interrupted' flag. If you're doing I/O operations or calling Thread.sleep() then the flag gets checked in those and an InterruptedException will get thrown. If you do neither of those things, you can check it yourself using Thread.currentThread().isInterrupted() and throw the exception.
Related
I have been checking similar questions.
This one is quite similar what I want to ask but not really I have the answer. Also This question I have checked.
Question that I have is that I have a SwingWorker which does long processes in the background.
#Override
protected final List<Object> doInBackground() throws Exception
{
//Should I add if(this.isCancelled) here?
List<Object> objectList = someFecthingMethod();
//Should I add if(this.isCancelled) here?
objectList.forEach(object -> executor.submit(new Helper(object));
this.latch.await();
//Should I add if(this.isCancelled) here?
someOtherLongRunningMethodBasedOnHelperResults();
}
In scratch I have a code like that. This runs when calculate button of mine which triggers the worker when it is clicked. I also want to be able to cancel it. I have written needed method stop() where it has cancel() method of worker itself.
Like below in my Worker Class I have my stop method like below:
#Override
public boolean stop()
{
return this.cancel( true );
}
When I call this method, I check in doInBackground(), this.isCancelled() returns true.. But anyway it keeps executing the methods within doInBackground().
So my question is that, should I be adding if(this.isCancelled()) check before every method in doInBackground() to stop it immediately, is there any better way to do stop it from executing when its canceled?
Thank you in advance.
You can create a wrapper around that provides the ability to cancel the latch. It will need to track the waiting threads and release them when they timeout as well as remember that the latch was cancelled so future calls to await will interrupt immediately.
The following code leads to java.lang.IllegalThreadStateException: Thread already started when I called start() method second time in program.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
This happens the second time updateUI.start() is called. I've stepped through it multiple times and the thread is called and completly runs to completion before hitting updateUI.start().
Calling updateUI.run() avoids the error but causes the thread to run in the UI thread (the calling thread, as mentioned in other posts on SO), which is not what I want.
Can a Thread be started only once? If so than what do I do if I want to run the thread again? This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
From the Java API Specification for the Thread.start method:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
Furthermore:
Throws:
IllegalThreadStateException - if the thread was already started.
So yes, a Thread can only be started once.
If so than what do I do if I want to
run the thread again?
If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Exactly right. From the documentation:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
In terms of what you can do for repeated computation, it seems as if you could use SwingUtilities invokeLater method. You are already experimenting with calling run() directly, meaning you're already thinking about using a Runnable rather than a raw Thread. Try using the invokeLater method on just the Runnable task and see if that fits your mental pattern a little better.
Here is the example from the documentation:
Runnable doHelloWorld = new Runnable() {
public void run() {
// Put your UI update computations in here.
// BTW - remember to restrict Swing calls to the AWT Event thread.
System.out.println("Hello World on " + Thread.currentThread());
}
};
SwingUtilities.invokeLater(doHelloWorld);
System.out.println("This might well be displayed before the other message.");
If you replace that println call with your computation, it might just be exactly what you need.
EDIT: following up on the comment, I hadn't noticed the Android tag in the original post. The equivalent to invokeLater in the Android work is Handler.post(Runnable). From its javadoc:
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* #param r The Runnable that will be executed.
*
* #return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
So, in the Android world, you can use the same example as above, replacing the Swingutilities.invokeLater with the appropriate post to a Handler.
No, we cannot start Thread again, doing so will throw runtimeException java.lang.IllegalThreadStateException.
>
The reason is once run() method is executed by Thread, it goes into dead state.
Let’s take an example-
Thinking of starting thread again and calling start() method on it (which internally is going to call run() method) for us is some what like asking dead man to wake up and run. As, after completing his life person goes to dead state.
public class MyClass implements Runnable{
#Override
public void run() {
System.out.println("in run() method, method completed.");
}
public static void main(String[] args) {
MyClass obj=new MyClass();
Thread thread1=new Thread(obj,"Thread-1");
thread1.start();
thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
}
}
/*OUTPUT in run() method, method completed. Exception in thread
"main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
*/
check this
The just-arrived answer covers why you shouldn't do what you're doing. Here are some options for solving your actual problem.
This particular thread is doing some
calculation in the background, if I
don't do it in the thread than it's
done in the UI thread and the user has
an unreasonably long wait.
Dump your own thread and use AsyncTask.
Or create a fresh thread when you need it.
Or set up your thread to operate off of a work queue (e.g., LinkedBlockingQueue) rather than restarting the thread.
What you should do is create a Runnable and wrap it with a new Thread each time you want to run the Runnable.
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
It is as you said, a thread cannot be started more than once.
Straight from the horse's mouth: Java API Spec
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
If you need to re-run whatever is going on in your thread, you will have to create a new thread and run that.
To re-use a thread is illegal action in Java API.
However, you could wrap it into a runnable implement and re-run that instance again.
Yes we can't start already running thread.
It will throw IllegalThreadStateException at runtime - if the thread was already started.
What if you really need to Start thread:
Option 1 ) If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Can a Thread be started only once?
Yes. You can start it exactly once.
If so than what do I do if I want to run the thread again?This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
Don't run the Thread again. Instead create Runnable and post it on Handler of HandlerThread. You can submit multiple Runnable objects. If want to send data back to UI Thread, with-in your Runnable run() method, post a Message on Handler of UI Thread and process handleMessage
Refer to this post for example code:
Android: Toast in a thread
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
I have had to fix a resource leak that was caused by a programmer who created a Thread but instead of start()ing it, he called the run()-method directly. So avoid it, unless you really really know what side effects it causes.
I don't know if it is good practice but when I let run() be called inside the run() method it throws no error and actually does exactly what I wanted.
I know it is not starting a thread again, but maybe this comes in handy for you.
public void run() {
LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();
try {
NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
Thread.sleep(5000);
if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
System.out.println("{There was a NetworkState change!}");
run();
} else {
run();
}
} catch (SocketException | InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
checkingNetworkStates.start();
}
Hope this helps, even if it is just a little.
Cheers
The following code leads to java.lang.IllegalThreadStateException: Thread already started when I called start() method second time in program.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
This happens the second time updateUI.start() is called. I've stepped through it multiple times and the thread is called and completly runs to completion before hitting updateUI.start().
Calling updateUI.run() avoids the error but causes the thread to run in the UI thread (the calling thread, as mentioned in other posts on SO), which is not what I want.
Can a Thread be started only once? If so than what do I do if I want to run the thread again? This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
From the Java API Specification for the Thread.start method:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
Furthermore:
Throws:
IllegalThreadStateException - if the thread was already started.
So yes, a Thread can only be started once.
If so than what do I do if I want to
run the thread again?
If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Exactly right. From the documentation:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
In terms of what you can do for repeated computation, it seems as if you could use SwingUtilities invokeLater method. You are already experimenting with calling run() directly, meaning you're already thinking about using a Runnable rather than a raw Thread. Try using the invokeLater method on just the Runnable task and see if that fits your mental pattern a little better.
Here is the example from the documentation:
Runnable doHelloWorld = new Runnable() {
public void run() {
// Put your UI update computations in here.
// BTW - remember to restrict Swing calls to the AWT Event thread.
System.out.println("Hello World on " + Thread.currentThread());
}
};
SwingUtilities.invokeLater(doHelloWorld);
System.out.println("This might well be displayed before the other message.");
If you replace that println call with your computation, it might just be exactly what you need.
EDIT: following up on the comment, I hadn't noticed the Android tag in the original post. The equivalent to invokeLater in the Android work is Handler.post(Runnable). From its javadoc:
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* #param r The Runnable that will be executed.
*
* #return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
So, in the Android world, you can use the same example as above, replacing the Swingutilities.invokeLater with the appropriate post to a Handler.
No, we cannot start Thread again, doing so will throw runtimeException java.lang.IllegalThreadStateException.
>
The reason is once run() method is executed by Thread, it goes into dead state.
Let’s take an example-
Thinking of starting thread again and calling start() method on it (which internally is going to call run() method) for us is some what like asking dead man to wake up and run. As, after completing his life person goes to dead state.
public class MyClass implements Runnable{
#Override
public void run() {
System.out.println("in run() method, method completed.");
}
public static void main(String[] args) {
MyClass obj=new MyClass();
Thread thread1=new Thread(obj,"Thread-1");
thread1.start();
thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
}
}
/*OUTPUT in run() method, method completed. Exception in thread
"main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
*/
check this
The just-arrived answer covers why you shouldn't do what you're doing. Here are some options for solving your actual problem.
This particular thread is doing some
calculation in the background, if I
don't do it in the thread than it's
done in the UI thread and the user has
an unreasonably long wait.
Dump your own thread and use AsyncTask.
Or create a fresh thread when you need it.
Or set up your thread to operate off of a work queue (e.g., LinkedBlockingQueue) rather than restarting the thread.
What you should do is create a Runnable and wrap it with a new Thread each time you want to run the Runnable.
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
It is as you said, a thread cannot be started more than once.
Straight from the horse's mouth: Java API Spec
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
If you need to re-run whatever is going on in your thread, you will have to create a new thread and run that.
To re-use a thread is illegal action in Java API.
However, you could wrap it into a runnable implement and re-run that instance again.
Yes we can't start already running thread.
It will throw IllegalThreadStateException at runtime - if the thread was already started.
What if you really need to Start thread:
Option 1 ) If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Can a Thread be started only once?
Yes. You can start it exactly once.
If so than what do I do if I want to run the thread again?This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
Don't run the Thread again. Instead create Runnable and post it on Handler of HandlerThread. You can submit multiple Runnable objects. If want to send data back to UI Thread, with-in your Runnable run() method, post a Message on Handler of UI Thread and process handleMessage
Refer to this post for example code:
Android: Toast in a thread
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
I have had to fix a resource leak that was caused by a programmer who created a Thread but instead of start()ing it, he called the run()-method directly. So avoid it, unless you really really know what side effects it causes.
I don't know if it is good practice but when I let run() be called inside the run() method it throws no error and actually does exactly what I wanted.
I know it is not starting a thread again, but maybe this comes in handy for you.
public void run() {
LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();
try {
NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
Thread.sleep(5000);
if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
System.out.println("{There was a NetworkState change!}");
run();
} else {
run();
}
} catch (SocketException | InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
checkingNetworkStates.start();
}
Hope this helps, even if it is just a little.
Cheers
I am new to Java concurrecny and I am reading this at the moment: Java Tutorial-Interrupts But I can't really understand where and why I should use an Interrupt. Can someone give me an example (code) so I better understand it? thx
Interrupts are used when you want to (cough) interrupt the thread -- typically meaning stop it from operating. Thread.stop() has been deprecated because of various issues so Thread.interrupt() is the way that you tell the thread that it should cease running -- it should cleanup what it is doing and quit. In reality, the programmer can use the interrupt signal on a thread in any way that they want.
Some examples:
Your thread might be sleeping for a minute and then spidering a web-page. You want it to stop this behavior.
Maybe you have a thread which is consuming from a queue of jobs and you want to tell it that no more jobs are coming its way.
Maybe you have a number of background threads that you want to interrupt because the process is shutting down and you want to do so cleanly.
There are certainly many ways to accomplish the above signaling but interrupt can be used.
One of the more powerful ways that Thread.interrupt() affects a running thread is by throwing InterruptedException from a couple different methods including Thread.sleep(), Object.wait(), and others.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// i've been interrupted
// catching InterruptedException clears the interrupt status on the thread
// so a good pattern is to re-interrupt the thread
Thread.currentThread().interrupt();
// but maybe we want to just kill the thread
return;
}
Also, often in a thread we are looping doing some task and so we check for interrupt status:
while (!Thread.currentThread().isInterrupted()) {
// keep doing our task until we are interrupted
}
With multi-threading, the idea is that you have some work that you divide up among several threads. The classic example would be to have a thread that does a background calculation or a background action such as a server query that will take a fair amount of time without doing that action in the main thread that handles the user interface.
By offloading those actions that might take a noticeable amount of time, you can prevent the user interface from seeming to get stuck. An example of this would be when you start an action in a displayed dialog, go to another window then return to the displayed dialog and the dialog does not update itself when you click on it.
Sometimes the background activity needs to be stopped. In that case you would use the Thread.interrupt() method to request that the thread stop itself.
An example might be if you have a client that is getting status information from a server once a second. The background thread handles the communication to the server and getting the data. The user interface thread takes the data and updates the display. Then the user presses a Stop or Cancel button on the display. The user interface thread then does an interrupt on the background thread so that it will stop requesting the status information from the server.
In concurrent programming, many programmers arrive at the conclusion that they need to stop a thread. They decide it would be a good idea to have some sort of boolean flag to tell indicate to the thread that it should stop. The interrupt flag is that boolean mechanism provided through the Java standard library.
For example:
class LongIterativeTask implements Runnable {
public void run() {
while (!thread.isInterrupted()) { //while not interrupted
//do an iteration of a long task
}
}
}
class LongSequentialTask implements Runnable {
public void run() {
//do some work
if (!thread.isInterrupted()) { //check flag before starting long process
//do a lot of long work that needs to be done in one pass
}
// do some stuff to setup for next step
if (!thread.isInterrupted()) { //check flag before starting long process
//do the next step of long work that needs to be done in one pass
}
}
}
I have running thread that I would like to stop and later on resume at some point. I learned not to use stop() etc. as these are deprecated and got to this code below that seems to stop thread successfully. It simply exits run method. Now, how can I restart it? If I call start() method it says that thread is still running, so would directly calling run() do in this situation? Would it cause any problems? BTW this is for Android app if that makes any difference.
private volatile stopThread;
public void stopButton() {
// this is called when button is clicked
// and thread is already started and running
stopThread= true;
}
public void run() {
while (!stopThread) {
// do something here
}
stopThread=false;
}
EDIT: its a timer that starts when thread is started, then can be paused and started again. So timer is a class containing Thread object (I already extend the class with SurfaceView).
The only safe way to stop and resume a thread safely is to add code at the relevant points in the thread's body to deal with it. (Don't use the deprecated Thread stop / pause / resume because they are fundamentally unsafe.)
Stop without resumption is relatively simple, using either an application-specific flag, or the Thread.interrupt() mechanism. The latter is probably better because some of Java's synchronization and IO APIs are interrupt-aware. However, you do run against the problem that a lot of existing libraries are not interrupt aware, or don't deal with InterruptedException properly.
Stop with resumption is more tricky. You'll need to create your own class something like this:
public class PauseControl {
private boolean needToPause;
public synchronized void pausePoint() {
while (needToPause) {
wait();
}
}
public synchronized void pause() {
needToPause = true;
}
public synchronized void unpause() {
needToPause = false;
this.notifyAll();
}
}
and add calls to myPauseControl.pausePoint() at relevant points throughout your the thread's code. Note that this won't allow you to pause IO, or activity in "child" threads, and it will only pause at points in your code where you call the pausePoint method. Also you need to beware of creating problems by pausing the thread while it holds locks on something else, or while something else is waiting for it to respond.
The Java 1.4 docs explained why and gave alternatives to the various deprecated Thread methods, including suspend() and resume() by using wait() and notify() instead.
Look for the heading What should I use instead of Thread.suspend and Thread.resume? about halfway down the page.
The stop() method of Thread class is deprecated and unsafe for use, because stopping a Thread causes it to unlock all monitors that it had locked. This has damaging consequences, because any of the Objects (previously protected by monitors) in an inconsistent state may now be viewed by other threads in an inconsistent state. This behavior may be subtle and difficult to detect.
You never invoke the run() method directly and if you stop the Thread using your volatile variable approach, the Thread would have TERMINATED. In order to start the Thread perform new Thread().start() again.