Re: threads and GUIs
LC's No-Spam Newsreading account wrote:
Apparently Lew did understand it, and gave a reply meaningful and useful
for me.
I'm glad because I honestly didn't understand it (and still don't, really).
You can't call start() twice on the same Thread. You are. Fix that.
That something I did not realize. I imagined that start() will invoke
It's clearly documented but it's also a "gotcha." Lot's of folks miss it.
The concept of local and global are known to me, although my background
from 30 years of Fortran (hope that doesn't make you laugh) tend to
privileges local variables unless things are in COMMON blocks. What I
This could be a bit of an issue. Java prefers to pass arguments to
methods rather than using globals; Java technically doesn't even have
globals, you use class variables instead. Trying to use "globals" is
one of the more difficult things you can do with multi-threaded
programming.
SwitchPinger sw4 = new SwitchPinger(4,0,5);
tsw4 = new Thread(sw4);
tsw4.start();
This global still bugs me. When does this happen? Can the user kick
off two such threads? What happens in that assignment to tsw4 if
there's already a tsw4 running?
Rather than just one holder for a single thread, you might want to look
into using a Executor as your "global," or something like a synchronized
List or Map. Both of those are thread safe and might avoid some of the
problems you are having.
I need tsw4 to be global, since the GUI shall define an action for a
"break" button which does
tsw4.interrupt();
Again, how many such "tsw4" threads could possibly be running at one
time? Do you restrict them to exactly one? Where and how?
Possibly I'd still have to look in SwingWorker. Or finally do a SCCE,
which I hoped to avoid, since I'm just inserting bit by bit into the
swing application code which did work in a non-swing one.
At present what happens is the following :
- main calls invokeAndWait for the wrapper which does the GUI
(I replaced invokeLater followed by a sleep(1000) with this)
- main calls workHorse()
the first loop runs OK, and can be also interrupted pressing the
"break" button I put in the GUI
- the restart button runs again workHorse()
Yeah, here I think you could be running two threads at once, if you
aren't careful.
this runs OK (before it gave the IllegalThreadStateException), but
while running locks the GUI (the restart button "remains depressed"
and all the other buttons do not react), which means de facto the
thread is not interruptable
Locking the GUI happens because you are running your task inside the GUI
thread itself, so the GUI can't be updated. Using a Thread should
alleviate that, if done properly.
You can use what you have now, I think, if you are very careful. Don't
allow the user to click "restart" until they click "break" and the
(single, global) thread has terminated.
Also, every time you touch tsw4, you must synchronize on some common
object. You are sharing this object between two threads (as near as I
can tell) and access is not threads safe. Traditionally, for class
variables one synchronizes on the class itself.
public class MyMain {
private static Thread tsw4;
public static void workHorse() {
synchronize( MyMain.class ) {
// safe now, use the same "synchronize" statement when the gui
// accesses this variable too
if( tsw4 != null && tsw4.isAlive() ) {
System.err.out( "error, tsw4 already in use..." );
return;
}
// ok to make a new thread here...
}
}
}
I'm thinking though this would be easier if tsw4 were a SwingWorker
instead of a simple Thread. There's also probably better ways of
structuring this overall, if I had more time to think about it.