I have two threads. One is SwingWorker(RunnableFuture). Another is my thread that extends java.lang.Thread.
My thread every second checks if user clicked that Cancel button or not.
If user clicked then I must somehow interrupt or stop or kill SwingWorker thread.
The problem that inside my Thread I cannot access SwingWorker thread.
I tried to pass reference of SwingWorker to my thread but this does not work. Because I cannot access methods of SwingWorker thread other than by calling
Thread.currentThread(). But if I call this using reference to SwingWorker within my thread it always returns my Thread but not SwingWorker.
How can I access SwingWorker(RunnableFuture) thread inside my own thread?
You need to obtain a reference to the same SwingWorker you use for the processing and use it to pass the cancel command. I would not attempt to access the underlying Thread (there is no reason to. And no, calling stop() is not a reason, it is deprecated and if you do use it could cause issues. See the Thread#stop() API). Fortunately, SwingWorker has a canel(boolean withInterrupt) method which does the job well.
You will also need to program the task you run inside the SwingWorker to pay attention to the cancel command. It should:
1) catch InterruptedExceptions, then check the SwingWorker's isCanceled() method. If true, treat the combined signal as a force stop.
2) regularly and preemptively check the SwingWorker's isCanceled() method to see if the thread was canceled, and end gracefully if it was. This is especially important if you don't do things that can be interrupted.
In one tutorial on javacreed I found how to do that. But cancel method of SwingWorker does not stop SwingWorker.
Instead I must modify method executed in doInBackground to check if current thread was interrupted Thread.currentThread().isInterrupted().
But this makes very hard for me to make my swingworker applicable for many different methods which I want to achieve.
Because I need to modify every method which is executed in doInBackground to include that check if SwingWorker is interrupted or not.
That's why I created new thread to run every second to check if SwingWorker was interrupted by cancel(true) and if so I would need somehow to tell SwingWorker to really cancel. After I call cancel(true) method on SwingWorker then nothing happens and code inside doInBackground is still executing unless I check if it was interrupted and throw new exception if so.
It is not possible to do it safely (it is possible to do unsafely, but I won't perpetuate the problem). You are better off just checking the isCanceled() and/or isInterrupted() flags inside the task. Do so at key points (part of loop conditions, after writing data to a stream) and periodically if you have non-repeating task. Make sure that whenever you get the signal that all your resources get closed (streams flushed and closed, DB or network connections closed, anything which might hold memory cleaned, closed, or whatever the protocol is for cleanup).
That is the main problem with using Thread#stop(). If it works, then all the resources you use in the Thread are left in bad states, and that can cause issues that are impossible to fix.
Furthermore, the most expensive for me is not my code but jdbc code. This is where I have a 1 - 2 seconds delay.
I cannot modify jdbc code. And if for user delay is bigger, user might click Cancel button forever
and I will interrupt only after the most expensive job is done and my little code for milliseconds to process ResultSet is left to execute.
But if I could access SwingWorker thread from my own thread I would say if after 3 seconds SwingWorker is not finished then stop it .
Volodymyr Levytskyi wrote:Furthermore, the most expensive for me is not my code but jdbc code.
Ahh, but there is the rub, and part of the problem! A simple stop() might kill the thread, but what happens to the JDBC connection? What happens to the data in transfer? It would cause the database to go into an inconsistent state, and could, if the transaction had an insert or update involved, cause the DB to get into a bad state with bad data. It is precisely why you should not use a force-stop approach.
There are ways to get at this, though. For example, you could provide a method which cancels more aggressively. It calls the normal SwingWorker#cancel(true) but then also uses the SQL Statement's cancel() method to stop it from executing. This would cause a SQLException in the running code (stopping the long task) and provides the opportunity to rollback(). You would put this cancelAggressively() method inside the class which holds the long running task so that it can get access to the Statement that was used to execute the JDBC command.
Luan Cestari wrote:AFAIK, in swing it isn't expected to control the threads directly (you usually leaves that task to the container).
What container? Swing is just a GUI library, it has no special 'container.' You manage threads in it the same way you manage threads in any desktop app, manually. The only difference is that you are sure there is an event dispatch thread and you have to be careful what data is accessed in the EDT, what data is accessed outside the EDT, and how long a task runs when run in the EDT. Then again, these are the same concerns you have with any multi-threaded situation in Java.
I think there might be some other way (like observer pattern).
Observer pattern is nice for observing data between threads. Can you expound on how you might use that to manage threads?
Luan Cestari wrote:Sorry, I misunderstood (I thought he wanted to kill EDT). If he have the reference of SwingWorker , he could call the cancel method  right?
Yes, as I mentioned in my first response and the OP acknowledged he knew in his second post. Did you see why he didn't think that was the solution? (in fact, it is the solution, just not by itself).
I don't know =/ I think he is a bit confused, maybe he could paste a simplified model of his code in github and show us what he really have there (like just some classes to reproduce his scenario to we see).