threads and GUIs


G

Guest

I'm an occasional java programmer for my own utilities. Some applets and
servlets, and few standalone applications.

*) standalone with threads is OK

I've written a test standalone application which happily uses concurrent
threads (on one hand it pings hosts on the local LAN, on the other it
retrieves info on which machine is on which slot in a switch, via an
http connection to the switch itself). This application runs once, does
most of its task in the main() method and outputs the result to
terminal.

Now the next step would be to integrate it with a swing GUI.


*) standalone with swing is also OK

The only other swing standalone application I had (and which I routinely
use), was based on a standard tutorial. Let's call it myClass ...

- myClass extends JPanel

- its main method calls javax.swing.SwingUtilities.invokeLater
to run() a createAndShowGUI() wrapper.

- the wrapper creates a frame, instantiates a new myGui(), sets
it as content, and maps the frame

- myGui generates all the gui with buttons and text areas necessary
to establish my actions on a mysql database. One of the components
of the GUI is a JComponent bottom, which ...

... is initialized as bottom = new myClass(table) (where table
is a database table name obtained as args to the main)

... it is regularly removed and replaced with a new instance of
myClass as I continue to issue different mysql queries

- the constructor myClass manages internally a swing JTable


*) putting swing and threads together

In the next step I designed the layout of my new GUI and used
the same paradigm as above

- the "monitor" class extends JPanel
- its main() calls invokeLater to run() a createAndShowGUI() wrapper.
- the wrapper creates a frame with a new myGui()
- myGui generates all the gui with buttons etc.

Now, where should I run my (time-consuming) threads ? So far I
started with a single thread (the most time-consuming). I was unsure
whether to put it into a monitor() METHOD or in a new monitor()
CONSTRUCTOR.

In the latter case I use a static JComponent dummy; and do
dummy=new monitor();

monitor() at some point does a tsw4.start();
where tsw4 is a static Thread tsw4 = new Thread(sw4);
and sw4 is an instance of a class which handles the http
connection. All this defined once forever in the prologue (global
to my topmost class)

Anyhow, I can do something of what I want in both cases (method or
constructor) provided that the invocation of monitor() occurs in the
main() after a suitable delay (say Thread.sleep(1000);) from the
deferred creation of the GUI.

monitor() can run once, and can display its status messages to the
GUI. I can also use a button to break the thread tsw4 and update
the status.

In the future monitor() should become an infinite loop, which
should run all his threads to completion, display results, wait
for a programmable interval, and re-run the threads etc.

The idea is that I could break the threads (which I can already do)
and then use a button to start a new monitor

So far my "break" button does :

tsw4.interrupt();
dummy=null;

and my "restart" button does :

dummy=new monitor();

Actually I tried to put the dummy=null; soon after the interrupt
or soon before the new monitor();

In both cases I get a java.lang.IllegalThreadStateException on the
tsw4.start(); statement in the monitor() constructor

but what is the state of the thread ?
(and why is it illegal ?)

Note that monitor() does no graphics of its own. I tried also with a
monitor() method, and to call it in various places, but with obviously
worse results (e.g. monitor() giving null pointer if GUI start is not
completed, the GUI waiting to show up until monitor() threads are
completed, monitor() giving null pointer when trying to write to a
message area in the GUI, or simply monitor can run once, but a new run
is ineffective)
 
Ad

Advertisements

L

Lew

LC's No-Spam Newsreading account said:
I'm an occasional java [sic] programmer for my own utilities. Some applets and
servlets, and few standalone applications.
...
*) standalone with swing [sic] is also OK

The only other swing [sic] standalone application I had (and which I routinely
use), was based on a standard tutorial. Let's call it myClass ...

Class names by convention should begin with an upper-case letter.
...
*) putting swing [sic] and threads together

In the next step I designed the layout of my new GUI and used
the same paradigm as above

- the "monitor" class extends JPanel

Class names by convention should begin with an upper-case letter.
- its main() calls invokeLater to run() a createAndShowGUI() wrapper.
- the wrapper creates a frame with a new myGui()
- myGui generates all the gui with buttons etc.

Now, where should I run my (time-consuming) threads ? So far I

started with a single thread (the most time-consuming). I was unsure
whether to put it into a monitor() METHOD or in a new monitor()
CONSTRUCTOR.

Don't start threads from constructors.
...
Note that monitor() does no graphics of its own. I tried also with a
monitor() method, and to call it in various places, but with obviously
worse results (e.g. monitor() giving null pointer if GUI start is not
completed, the GUI waiting to show up until monitor() threads are
completed, monitor() giving null pointer when trying to write to a
message area in the GUI, or simply monitor can run once, but a new run
is ineffective)

Cannot fully answer without <http://sscce.org/>, but I'm betting it has
something to do with trying to spawn a thread from a constructor.

All that 'dummy=null' stuff is highly suspicious, too.
 
M

markspace

LC's No-Spam Newsreading account said:
In both cases I get a java.lang.IllegalThreadStateException on the
tsw4.start(); statement in the monitor() constructor

but what is the state of the thread ?
(and why is it illegal ?)


Probably because you have already called start() on that thread.
Threads can only be started once.

It sounds to me like you still have some concurrency problems.

Note that monitor() does no graphics of its own. I tried also with a
monitor() method, and to call it in various places, but with obviously


The problem is that Monitor is a JPanel, which has some implications of
it's own, i.e., it still needs to be thread safe. Quoting you from some
stuff earlier in your post:

> monitor() at some point does a tsw4.start();
> where tsw4 is a static Thread tsw4 = new Thread(sw4);
> and sw4 is an instance of a class which handles the http
> connection. All this defined once forever in the prologue (global
> to my topmost class)
>


This strikes me as a problem. If sw4 truly is an instance, then you are
almost certainly going to have threading problems. I would make a new
sw4 instance each time you use it:

SW4 sw4 = new SW4();
new Thread( sw4 ).start();

Not bomb proof, but still more likely to be correct and more robust in
the long term.


On a more fundamental level, I think you should be using a SwingWorker.
This class makes it much easier to write thread safe Swing programs.
It handles the threading for you so you don't have to. Give your
Monitor class a "setResult( Object )" method (which does not have to be
thread safe) and do something like this:


public class HttpTask extends SwingWorker<Void, Object> {
@Override
public Void doInBackground() {
SW4 sw4 = new SW4();
sw4.run();
return null;
}

@Override
protected void done() {
try {
monitor.setResult(get());
} catch (Exception ignore) {
}
}
}

Now you can call this from anywhere, and it'll be safe(r):

(new HttpTask()).execute();

<http://java.sun.com/docs/books/tutorial/uiswing/concurrency/worker.html>

You also should lay off Thread.sleep(int), which will block the calling
thread. This is really bad for Swing. Use a Swing Timer instead to do
your timing tasks.

<http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html>
 
G

Guest

Probably because you have already called start() on that thread.
Threads can only be started once.

uh ? what happens to a thread when the threaded Runnable run() method
ends (ends or returns ? is it the same ?)
The problem is that Monitor is a JPanel, which has some implications

but should it be a JPanel in order to display a GUI ?

monitor.java is an application (therefore it shall contain a class of
the same name, and a main(). The main uses the standard swing idiom to
start a GUI. And THEN should execute the workhorse. I am not sure
whether the workhorse needs to be a constructor (there will be a single
instance of it), a method with the same name of the class, or a method
with an arbitrary name. Apparently it does not matter. The workhorse
does not do GUI-sh things of its own (except updating some gadgets in
the existing GUI, simplest case is writing messages to a message area).
This strikes me as a problem. If sw4 truly is an instance, then you are
almost certainly going to have threading problems. I would make a new sw4
instance each time you use it:

SW4 sw4 = new SW4();
new Thread( sw4 ).start();

I am not sure if what I mean by instance is the same you mean. At the
moment this is defined in the prologue, and I have a single object like
this.

static SwitchPinger sw4 = new SwitchPinger(4,0,5);

It is likely that in the future I'll add a new object sw0 with a thread
of its own.

static SwitchPinger sw0 = new SwitchPinger(0,6,6);

I will never have more than two of such. They are a class with a run()
method which interrogates a switch via http (slowly) using the same
interrogation procedure. Since we have two switches, I'll never need
more.

I'd like to wrap them in a thread, because they are slow. I found than
running them concurrently with other threads allows me to terminate
things faster (the other threads are faster but have a timeout (they do
an ARP ping via an external script), but are many ... I found threads an
effective way of limiting the number of concurrent ones to a threshold I
tuned. All this works nicely in a standalone (non-GUI) application.
On a more fundamental level, I think you should be using a SwingWorker.
<http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html>

I'll study those two things.
 
G

Guest

*) putting swing [sic] and threads together
- the "monitor" class extends JPanel
Class names by convention should begin with an upper-case letter.

I thougt the "main" class in an application should have the same name as
the .java source file. I use upper case (camel case) for directories.
Anyhow should be irrelevant as far runtime errors are concerned.
Don't start threads from constructors.

I do not want to. I'm not even sure a standalone application like this
needs a constructor (see reply to other message). Anyhow I have the same
problems using a constructor, or using a plain method.
All that 'dummy=null' stuff is highly suspicious, too.

That was just a blind attempt. I thought that if I did a repeated
dummy=new monitor(); I could incur in memory leaks.

Remember that I have a "break" button which should terminate the threads
started by monitor(). It does a tsw4.interrupt(); Monitor catches this
and terminates.

Then another "restart" button should execute monitor() again. Since it
is this which gives the error on the thread state, I thought may be it
had not yet disposed properly of the old monitor().

Anyhow the current version has no constructor and no dummy. Just calls
monitor();

and gives the same problem
 
M

markspace

LC's No-Spam Newsreading account said:
uh ? what happens to a thread when the threaded Runnable run() method
ends (ends or returns ? is it the same ?)


I don't understand this sentence. However, Runnable doesn't have a
start() method, and it doesn't throw IllegalThreadStateException, so you
have a Thread, not Runnable.

You can't call start() twice on the same Thread. You are. Fix that.

but should it be a JPanel in order to display a GUI ?


Not necessarily.

> I am not sure if what I mean by instance is the same you mean. At the
moment this is defined in the prologue, and I have a single object like
this.

static SwitchPinger sw4 = new SwitchPinger(4,0,5);


Yes, that's an instance. And it's a bad idea. Make this class just
before you need it.

SwitchPinger sw4 = new SwitchPinger(4,0,5);
new Tread( sw4 ).start();

Don't do this statically. Do it in a method when you need it to happen.

Also: Java has no "prologue" as far as I know. What you have is called
a static variable or a class variable. "Prologue" doesn't exist. What
I want you to use is called a local variable. Please look those terms
up because they are super important in Java.

Here's a start:
<http://java.sun.com/docs/books/tutorial/java/javaOO/classvars.html>
It is likely that in the future I'll add a new object sw0 with a thread
of its own.

static SwitchPinger sw0 = new SwitchPinger(0,6,6);


SwitchPinger sw4 = new SwitchPinger(0,6,6);
new Tread( sw4 ).start();

So? Same as before. Don't do this statically. Don't make this a class
or instance variable. Use a local variable.

With no code example, I can't be sure, but this is almost certainly a
source of potential problems.
 
Ad

Advertisements

L

Lew

LC's No-Spam Newsreading account said:
I thougt the "main" class in an application should have the same name as

Not just the "main" class but all public classes need to have the same
basename as the class name, in typical file system-based source /
class trees. Thus the bytecode for class "FooBar" would be in a file
"FooBar.class".

By convention, type, method and variable names are spelled in camel
case with an initial upper-case letter for types and an initial lower-
case letter for variables and methods. The exception is constants,
which are spelled in all upper case.

These conventions have been in place since Java first started getting
popular and are well documented on java.sun.com:
<http://java.sun.com/docs/codeconv/index.html>

There's some wiggle room on things like opening-brace placement,
indentation and how to capitalize intialisms like "URL", but the bulk
of the conventions are pretty universally and rigorously followed.
the .java [sic] source file. I use upper case (camel case) for directories.

Directories correspond to package names. By convention, not quite as
firm as other naming conventions, packages, and thus directories, are
spelled with all lower-case letters.

LC's No-Spam Newsreading account said:
I do not want to. I'm not even sure a standalone application like this
needs a constructor (see reply to other message). Anyhow I have the same

Every successfully compilable class needs and in fact has a
constructor whether you write one or not.
problems using a constructor, or using a plain method.

That doesn't mean that starting threads from a constructor is a good
idea. It just means that you have a different bug, which others in
this thread have already addressed.

LC's No-Spam Newsreading account said:
That was just a blind attempt. I thought that if I did a repeated
dummy=new monitor(); I could incur in memory leaks.

Blind attempts to fix problems tend to bump into walls. Why did you
think that pointing the 'dummy' reference to different instances would
incur memory leaks?
Remember that I have a "break" button which should terminate the threads
started by monitor(). It does a tsw4.interrupt();  Monitor catches this
and terminates.

Then another "restart" button should execute  monitor() again. Since it
is this which gives the error on the thread state, I thought may be it
had not yet disposed properly of the old monitor().

As others have stated, you cannot restart a thread that has
terminated. That results in an 'IllegalThreadStateException '.
Anyhow the current version has no constructor and no dummy. Just calls
     monitor();

and gives the same problem

You say that as if we could somehow magically read your mind to know
what's in or not in your code.

Do not ignore <http://sscce.org/>, previously recommended. How do you
expect anyone to give meaningful answers when you don't give any
relevant details?

GIGO: Garbage in, garbage out. If you don't give good data, you can't
get good answers.
 
L

Lew

LC's No-Spam Newsreading account said:
uh ? what happens to a thread when the threaded Runnable
run() method ends (ends or returns ? is it the same ?)

It just hangs around until and unless all references to it go away. Once a
thread object is dereferenced in your code and is no longer alive, it becomes
eligible for garbage collection (GC).

When a method ends, it returns.

LC's No-Spam Newsreading account said:
monitor.java is an application (therefore it shall contain a class of
the same name, and a main(). The main uses the standard swing [sic] idiom to
start a GUI. And THEN should execute the workhorse. I am not sure
whether the workhorse needs to be a constructor (there will be a single

The phrasing "be a constructor" is inapplicable. Your "workhorse" will be an
instance of a class, which must be constructed before it can be used.
instance of it), a method with the same name of the class, or a method
with an arbitrary name. Apparently it does not matter. The workhorse

It does matter. First of all, there should not be any method with the same
name as the owning class; that's a recipe for confusion with constructors.
Second, it is dangerous to spawn threads from inside a constructor. Memory
visibility is not guaranteed until the constructor completes. The only safe
option is to spawn a thread from a method invoked after construction is
complete (and with a different name from the class's constructors).
does not do GUI-sh things of its own (except updating some gadgets in
the existing GUI, simplest case is writing messages to a message area).

"Does not do X except for Y" means "Does do X". The doublespeak increases the
risk of bugs in your code.
I am not sure if what I mean by instance is the same you mean. At the

The term "instance" has a well-defined and particular meaning in
object-oriented programming, and in Java specifically. It means an object
constructed on the heap. At the bottom, you obtain an instance by
constructing it (using a 'new' expression), and access it through a reference
to that instance.

Link to the Javadocs can be found upthread.

LC's No-Spam Newsreading account said:
I'll study those two things.

You might consider also reviewing the online Java tutorials and the Java
Language Specification (JLS) for the details of types and instances and how
they're constructed and referenced.
 
G

Guest

I don't understand this sentence.

Apparently Lew did understand it, and gave a reply meaningful and useful
for me.
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
the run() method of the thread "argument", and that when that
terminated, the thread could be started again. I even tested
tsw4.isAlive() [in order to write a idle/running message in a text
label] before start, after start, and after a tsw4.join() and imagined
that "alive" or not could be the only status.
Also: Java has no "prologue" as far as I know. What you have is
called a static variable or a class variable. "Prologue" doesn't
exist. What I want you to use is called a local variable.

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
(improperly) called "prologue" is the list of class variables defined in
the source file after the first class statement and before main(),
eventual constructors or other methods, which are global not only to the
"main" class but also to its other inner classes. Remember that I'm
writing standalone applications.
Yes, that's an instance. And it's a bad idea. Make this class just
before you need it.

I thought that doing an instance of SwitchPinger each time (with the
idea to run things in a loop, currently instead iterations beyond the
first are activated manually) would somehow waste memory.
SwitchPinger sw4 = new SwitchPinger(4,0,5);
new Tread( sw4 ).start();
Don't do this statically. Do it in a method when you need it to happen.

Done it (in fact the original non-GUI version did exactly that).
This gets rid of the IllegalThreadStateException

But I cannot use a pure local variable. I do instead

static Thread tsw4=null; // in the prologue :)

Then in the workHorse (which is a method and not a constructor, I have
no explicit constructors now) I do

SwitchPinger sw4 = new SwitchPinger(4,0,5);
tsw4 = new Thread(sw4);
tsw4.start();

I need tsw4 to be global, since the GUI shall define an action for a
"break" button which does

tsw4.interrupt();

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()

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
 
G

Guest

Not just the "main" class but all public classes need to have the same
basename as the class name, in typical file system-based source /
class trees. Thus the bytecode for class "FooBar" would be in a file
"FooBar.class".

Please remember that I'm an occasional java programmer (scientist with
[long] Fortran programming background). I'd hardly write general purpose
reusable classes (alike to libraries of subroutines for me). What I
usually need are standalone applications with a main() and few other
methods. So I'd have a single myapp.java source file (with inner classes
if I find convenient or I'm forced to put thing in other classes).
Directories correspond to package names.

I was not thinking of java development (I know what they are, and put my
hands on things which a younger programmer wrote for me). I was mainly
thinking of "everyday's life".

For me a directory contains things related to a project, a satellite, a
celestial source, a paper, a software package (oy yes :)) etc. And are
these names which I put with capital initials.

Files can be program sources or executables, shell scripts, tex sources,
data files, plain text, other documents etc. And for these I use
lowercase. All uppercase is only for README or alike :)

Every successfully compilable class needs and in fact has a
constructor whether you write one or not.

The "typical application" I'm thinking of is a standalone main(). So if
I know I can avoid to write a constructor for something which will
exist in a single instance, I will.
That doesn't mean that starting threads from a constructor is a good
idea.

I've taken note.
Do not ignore <http://sscce.org/>, previously recommended.

As I said, I hoped to avoid it since I already had a working non-swing
standalone app, and a dummy swing app with just the GUI. I wanted to
"reverse" bits by bits pieces from the main() of the non-swing one into
some appropriate method of the new app.

But I cannot come to an end soon, I will do a SSCCE.
 
G

Guest

On a more fundamental level, I think you should be using a SwingWorker.

Read a bit about it (luckily I have a java6 since a while) and
implemented a wrapper according to your suggestion ...
(new HttpTask()).execute();

.... although I used a different name
Give your Monitor class a "setResult( Object )" method

.... done with a totally dummy one

public static void setResult( Object o) { }
public class HttpTask extends SwingWorker<Void, Object> {

the only modification is that I had to add "static"
public static class ...

to prevent compile error "non-static variable this cannot be
referenced from a static context" on
( new TheRealStuffIsHere()).execute();

With the replacement of the invocation of workHorse() with the above
statement both in the main() after GUI setup (for the first iteration),
or in the code activated by the reload button (for subsequent
iterations), now the method which contains the threads can run in all
cases, and can be interrupted by break in all cases !

Thanks !
 
Ad

Advertisements

L

Lew

LC's No-Spam Newsreading account said:
I thought that doing an instance of SwitchPinger each time (with the
idea to run things in a loop, currently instead iterations beyond the
first are activated manually) would somehow waste memory.

Java manages memory for you. When an instance no longer has any references to
it reachable from the live program, i.e., the instance becomes unreachable, it
is eligible for garbage collection (GC) to delete it.

In a loop like:

for ( Item item : stuff )
{
Foo foo = new Foo();
foo.process( item );
}

a new 'Foo' is created within each iteration of the loop. Clearly there are
no other references to that new instance (unless 'process()' does something
weird - we'll assume not). As each loop iteration closes, the 'foo' reference
goes out of scope and the 'Foo' instance becomes unreachable. GC will
eventually collect and destroy the unreachable references if it thinks the
memory is needed.

Java is optimized for short-lived objects, ones that become unreachable
quickly. If the 'Foo' instance were created outside the loop and refilled
each time, the loop could be slower and memory pressure would likely increase,
not decrease. That's because Java GC uses different strategies for short- and
long-lived objects.

Java doesn't actually have memory leaks. What we Java folks call "leaks" are
actually the opposite - memory references that are not released, leaving
objects still reachable, ergo uncollectible, eventually causing the dreaded
'OutOfMemoryError' ("OOME" colloquially).

As in paths to inner peace, the guiding principle for harmonious object
management in Java is, "Let it go."
 
R

Roedy Green

You are asking for very specific help with your code without revealing
the code itself. If the code is too long to post, post it on the
Internet somewhere and post a URL. If you have not got a place to post
it, just ask and likely someone here can accommodate you.

For some background information, in case you missed something, see
http://mindprod.com/jgloss/swingthreads.html
--
Roedy Green Canadian Mind Products
http://mindprod.com

Without deviation from the norm, progress is not possible.
~ Frank Zappa (born: 1940-12-21 died: 1993-12-04 at age: 52)
 
L

Lew

LC's No-Spam Newsreading account said:
the only modification is that I had to add "static"
public static class ...

to prevent compile error "non-static variable this cannot be
referenced from a static context" on
( new TheRealStuffIsHere()).execute();

You had another choice - to create an instance of the enclosing class and
invoke the inner-class constructor through that instance. It is likely that
your approach to make the nested class 'static' rather than inner was the
correct one.

There are times when it's better to make a nested class inner (non-'static'),
such as to give access to members of the enclosing class instance.
 
M

markspace

LC's No-Spam Newsreading account said:
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).

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.
 
Ad

Advertisements

M

markspace

LC's No-Spam Newsreading account said:
With the replacement of the invocation of workHorse() with the above
statement both in the main() after GUI setup (for the first iteration),
or in the code activated by the reload button (for subsequent
iterations), now the method which contains the threads can run in all
cases, and can be interrupted by break in all cases !


Good, I'm glad you got it sorted. I posted another reply upthread
before I read this post, there still might be some useful information
for you.

I don't discount the possibility of further multi-threading issues,
however that SwingWorker is 90% thread safe and should keep you out of
the worst troubles.
 
G

Guest

LC's No-Spam Newsreading account wrote:
This global still bugs me. When does this happen? Can the user kick
off two such threads?
Again, how many such "tsw4" threads could possibly be running at one
time? Do you restrict them to exactly one? Where and how?

In principle the user should not do this, unless by mistake. There are
easy ways out of this, like disabling/enabling the buttons
conditionally, or using some form of lock boolean variable (the CGI this
application is going to replace used a lock file).

Most important, I will be THE (only) user of this application !
Also, every time you touch tsw4, you must synchronize on some common object.

I'll re-read the part of the tutorial on synchronization.
I'm thinking though this would be easier if tsw4 were a SwingWorker
instead of a simple Thread.

As you already realized from my later replies, a SwingWorker wrapping
my entire work horse routine seems to do what I want nicely
 
Ad

Advertisements

T

Teraposa Lunodas

I am not sure if what I mean by instance is the same you mean. At the
moment this is defined in the prologue, and I have a single object
like
this.

static SwitchPinger sw4 = new SwitchPinger(4,0,5);

It is likely that in the future I'll add a new object sw0 with a
thread
of its own.

static SwitchPinger sw0 = new SwitchPinger(0,6,6);

I will never have more than two of such. They are a class with a run()
method which interrogates a switch via http (slowly) using the same
interrogation procedure. Since we have two switches, I'll never need
more.

I'd like to wrap them in a thread, because they are slow. I found than
running them concurrently with other threads allows me to terminate
things faster (the other threads are faster but have a timeout (they
do
an ARP ping via an external script), but are many ... I found threads
an
effective way of limiting the number of concurrent ones to a threshold
I
tuned. All this works nicely in a standalone (non-GUI) application.
 
Ad

Advertisements


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top