Cancelling SwingWorker - java

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.

Related

How do you wait for a thread to finish in Java without freezing the GUI?

I am coding an android game in Eclipse with java. The main goal is to wait for a thread to finish, then to set a boolean to true. The reason is that when a user clicks a button it will only run if the boolean is true. However, when I call a method, it creates a thread and does its thing, then when it is done, it sets the boolean to true. However, it automatically sets the boolean to true while the thread is still running, and so the user can click the button (which messes some things up). Is there a way to wait for a thread to finish without freezing the screen? (thread.join() seems to be freezing it)
Any help is appreciated.
Seems like you don't really need to wait until the thread is done to continue, the way I see it you only need to be notified once it's done, the simplest approach for it would be passing a "callback listener" object to the thread, and execute it when done, this will let you know that you are ready to continue, OR a better approacch would be an AsyncTask which will allow you to do everything in background and when done you can use the onPostExecute method, hope this helps.
This is the way you create and add a callback to be notified when your thread has completed:
//Create your callback listener interface...
public interface MyThreadListener{
public void threadFinished();
}
//This is the method that runs some functionality in a separate thread
public void executeTaskInSeparateThread(final MyThreadListener listener){
new Thread(new Runnable() {
#Override
public void run() {
// DO your long task here...
//Notify when done before leaving run method...
listener.threadFinished();
}
}).start();
}
//Use it like this
//Create the implementation of the listener you want (this is something like what you usually do for buttons or any other android listener)
MyThreadListener listener = new MyThreadListener() {
#Override
public void threadFinished() {
//Do whatever you want when notified...
//NOTE: This method will be called on a separated thread too, you cannot modify views...
}
};
executeTaskInSeparateThread(listener);
Once the thread completed it will execute the listener and will let you know is done...
Regards!
Q: Why not set the button to "disabled" when you start the thread (btn=.setEnabled(false);), then have the thread set the button to "enabled" just before it exits?
And yes, calling "thread.join()" (or ANY blocking call) from your UI thread will indeed "freeze" it :)
PS:
Are you using a Java thread, or an Android "Asynch Task"? Here's an excellent tutorial on the latter:
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
Use an AsyncTask. In onPreExecute() disable your button so the user cannot click it again.
In onPostExecute method enable the button again. Do the time consuming logic in the doInBackground method.
try to create a Task extends AsyncTask, override the doinBackground mothed,Then put "time-consuming operation" in it. When your task done,it'll goto "onPostExecute",just use an Interface call back to the Actiity and enable the Button . When you use the AsyncTask you should know that: The Default AsyncTask has got a "pool",System allow 5 instace of AsyncTask ,if you got more than 5 Task,you should create a no limit pool.
My English is so so bad,lol.

Interrupt a thread in java

I found this solution to know if a thread has been interrupted.
public class OurThread extends Thread(){
private volatile boolean stop = false;
public void run(){
while (!stop) {
//Do your actions
}
}
}
But my run method is only executed once, so It doesnt make sense to put it insisde a while loop. Another approach I found, is to check the Thread.isInterrupted() flag, and then terminate the thread. My run() method is pretty long so I would have to check lots of times this condition making my code dirty.
I have to apply this into four diferents processes so im trying to find a simpler, cleaner soution. I was hoping if is there something like:
try{//my code}
catch(interrumption)
The problem is that since my thread is interrumped by using future.cancel(), the interruption is not thrown inside my run() code, then i cant do that either.
Any suggestion?
By now im checking lots of times between the code if the thread has been cancelled.
Thanks :)
Firstly, don't extend Thread, you should implement Runnable or Callable.
Secondly you can add a method like
static void checkInterrupt() {
if(Thread.currentThread().isInterrupted())
throw new IllegalStateException("Interrupted");
}
and place this in the four places. This doesn't add much code and isn't as ugly as a task which won't stop.
Your task ( Runnable or Callable) can't be interrupted unless it has inbuilt mechanism to respond to interrupts. Also it depends on your design; like, when exactly task expects to be interrupted. Usually we do when the task has reached a safe state.
So you check if interrupt is received and then respond appropriately. To reuse code you can use approach suggested by #Peter.

Issues cancelling a swing worker

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.

destroy java thread

help me kill java thread
So I have code:
new Thread(new Runnable() {
public void run() {
// process() method is time-consuming and has no while-loop in his body
// so I want to give user to stop it
new AnyObject().process();
}
}).start();
My question is how can I kill such thread?
You can call Thread.stop() however you should understand what it does as its deprecated for a reason (being that it can leave your system in an inconsistent state) If the work you are doing is self contained and well behaved, it won't be a problem.
However if it were well behaved you wouldn't need to stop it this way, thus the catch-22 with this "solution" ;)
Ultimately the only safe way to stop a thread is to have it exit its run loop. There are two main ways to do that, set a flag that the AnyObject.process method checks periodically or have the AnyObject.process method respond correctly to an interrupt and exit. However to use the latter method, you will need to keep a reference to the thread around so you can issue the interrupt method on it.
You should probably keep a reference to your AnyObject as well in case you need to reference it later.
If all that fails, System.exit() will usually do the trick.
You can call interrupt() on thread in order to stop it.
you can use thread.interrupt() to stop thread!
Your Thread will be terminated when the run() method will be terminated.
In your example, it will be when the new AnyObject().process(); will be terminated.
So, terminate the process() method will terminate your Thread.

How does one stop a thread without a stop() method?

I have question about the Java threads. Here is my scenario:
I have a thread calling a method that could take while. The thread keeps itself on that method until I get the result. If I send another request to that method in the same way, now there are two threads running (provided the first did not return the result yet). But I want to give the priority to the last thread and don't want to get the results from the previously started threads. So how could I get rid of earlier threads when I do not have a stop method?
The standard design pattern is to use a local variable in the thread that can be set to stop it:
public class MyThread extends Thread {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// do your things
}
}
}
This way you can greacefully terminate the thread, i.e. without throwing an InterruptedException.
The best way really depends on what that method does. If it waits on something, chances are an interrupt will result in an InterruptedException which you handle and cleanly exit. If it's doing something busy, it won't:
class Scratchpad {
public static void main(String[] a) {
Thread t = new Thread(new Runnable() {
public void run() {doWork();}
});
t.start();
try {
Thread.sleep(50);
} catch (InterruptedException ie) {}
t.interrupt();
}
private static void doWork() {
for ( long i = 1; i != 0; i *=5 );
}
}
In the case above, the only viable solution really is a flag variable to break out of the loop early on a cancel, ala #inflagranti.
Another option for event-driven architectures is the poison-pill: if your method is waiting on a blocking queue for a new item, then you can have a global constant item called the "poison-pill" that when consumed (dequeued) you kill the thread:
try {
while(true) {
SomeType next = queue.take();
if ( next == POISON_PILL ) {
return;
}
consume(next);
}
} catch //...
EDIT:
It looks like what you really want is an executor service. When you submit a job to an executor service, you get back a Future which you can use to track results and cancel the job.
You can interrupt a Thread, its execution chain will throw an InterruptedException most of the time (see special cases in the documentation).
If you just want to slow down the other thread and not have it exit, you can take some other approach...
For one thing, just like exiting you can have a de-prioritize variable that, when set, puts your thread to sleep for 100ms on each iteration. This would effectively stop it while your other thread searched, then when you re-prioritize it it would go back to full speed.
However, this is a little sloppy. Since you only ever want one thing running but you want to have it remember to process others when the priority one is done, you may want to place your processing into a class with a .process() method that is called repeatedly. When you wish to suspend processing of that request you simply stop calling .process on that object for a while.
In this way you can implement a stack of such objects and your thread would just execute stack.peek().process(); every iteration, so pushing a new, more important task onto the stack would automatically stop any previous task from operating.
This leads to much more flexible scheduling--for instance you could have process() return false if there is nothing for it to do at which point your scheduler might go to the next item on the stack and try its' process() method, giving you some serious multi-tasking ability in a single thread without overtaxing your resources (network, I'm guessing)
There is a setPriority(int) method for Thread. You can set the first thread its priority like this:
Thread t = new Thread(yourRunnable);
t.start();
t.setPriority(Thread.MIN_PRIORITY); // The range goes from 1 to 10, I think
But this won't kill your thread. If you have only two threads using your runnable, then this is a good solution. But if you create threads in a loop and you always sets the priority of the last thread to minimum, you will get a lot of threads.
If this is what is application is going to do, take a look at a ThreadPool. This isn't an existing class in the Java API. You will have create one by yourself.
A ThreadPool is another Thread that manages all your other Threads the way you want. You can set a maximum number of running Threads. And in that ThreadPool, you can implement a system that manages the Thread priority automatically. Eg: You can make that older threads gain more priority, so you can properly end them.
So, if you know how to work with a ThreadPool, it can be very interesting.
According to java.lang.Thread API, you should use interrupt() method and check for isInterrupted() flag while you're doing some time-consuming cancelable operation. This approach allows to deal with different kind of "waiting situations":
1. wait(), join() and sleep() methods will throw InterruptedExcetion after you invoke interrupt() method
2. If thread blocked by java.nio.channels.Selector it will finish selector operation
3. If you're waiting for I/O thread will receive ClosedByInterruptException, but in this case your I/O facility must implement InterruptibleChannel interface.
If it's not possible to interrupt this action in a generic way, you could simply abandon previous thread and get results from a new one. You could do it by means of java.util.concurrent.Future and java.util.concurrent.ExecutorService.
Cosider following code snippet:
public class RequestService<Result> {
private ExecutorService executor = Executors.newFixedThreadPool(3);
private Future<Result> result;
public Future<Result> doRequest(){
if(result !=null){
result.cancel(true);
}
result = executor.submit(new Callable<Result>() {
public Result call() throws Exception {
// do your long-running service call here
}
});
return result;
}
}
Future object here represents a results of service call. If you invoke doRequest method one more time, it attempts to cancel previous task and then try to submit new request. As far as thread pool contain more than one thread, you won't have to wait until previous request is cancelled. New request is submitted immediately and method returns you a new result of request.

Categories