threadpool and ui paint

P

Philipp Kraus

Hello,

I have a lot of objects, which are calculated within a thread pool (by
a queue structure), so each object
as got an individual paint method for visualization. At the moment I
try to paint the objects within the threads
of the pool, but this creates exceptions.

Which is the correct way to do an UI painting? Each object needs an
individual paint structure, but all objects
can be painted after the thread has calculated the objects. In pseudo
code my structure shows:

class worker {
void run()
{

while (threadruns)
{
for all x = get object from queue
{
calculate x
push x back to the finish queue
- paint x -
}
- or here paint x -

thread await

for all y = ….
}

}

I'm a little bit confused with the Swing InvoceLater structure and in
which way I can imlemented this in my pool

Thanks

Phil
 
J

Joerg Meier

class worker {
void run()
{

while (threadruns)
{
for all x = get object from queue
{
calculate x
push x back to the finish queue
SwingUtilities.invokeLater(new Runnable() {
public void run() {
swingJLabelOrWhatever.setText(x);
}
});
}
- or here paint x -

thread await

for all y = ¡K.
}

}

You need to surround all access to Swing components that way.

Liebe Gruesse,
Joerg
 
E

Eric Sosman

Hello,

I have a lot of objects, which are calculated within a thread pool (by a
queue structure), so each object
as got an individual paint method for visualization. At the moment I try
to paint the objects within the threads
of the pool, but this creates exceptions.

Yeah. Nearly everything that's done to or with a UI component must
take place on the Event Dispatching Thread, or EDT. If you manipulate
UI components from other threads, bad things are likely to happen. See
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html
for an explanation and examples.
Which is the correct way to do an UI painting? Each object needs an
individual paint structure, but all objects
can be painted after the thread has calculated the objects. In pseudo
code my structure shows:

class worker {
void run()
{

while (threadruns)
{
for all x = get object from queue
{
calculate x
push x back to the finish queue
- paint x -
}
- or here paint x -

thread await

for all y = ….
}

}

I'm a little bit confused with the Swing InvoceLater structure and in
which way I can imlemented this in my pool

Your outline is all right, so long as you make sure "paint x"
happens on the EDT. That's what SwingUtilities.invokeLater() does:
You construct a Runnable that does the painting or whatever else is
desired, and you give that Runnable to invokeLater(). You can do
this on any thread you like, but when the Runnable actually runs it
will be on the EDT. So, "paint x" looks something like

final Thing x = ...;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
x.updateTheDisplay();
}
});

If you want to wait until all the calculating is finished
before updating the display, it might go like

final Collection<Thing> finished = ...;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (Thing x : finished) {
x.updateTheDisplay();
}
}
});

(By the way, Java 8 introduces a more compact notation for this sort
of thing -- but that's another story, and the old way still works.)

Finally, you'll do yourself a favor if you divide the Thing into
two pieces: A "model" that owns the data and is responsible for the
computations that modify it, and a "view" that listens for notices
that the model has changed. This may seem at first to be a rather
pointless division of labor, but trust me: It pays off. See
http://docs.oracle.com/javase/tutorial/uiswing/components/model.html
for an explanation of this separation.
 
M

markspace

SwingUtilities.invokeLater(new Runnable() {
public void run() {
swingJLabelOrWhatever.setText(x);
}
});

However, this is broken if 'x' is mutable. You can't mutate (change)
objects that are being accessed by more than one thread. You'll need to
synchronize 'x', and that can be a lot of hassle. The currency
tutorials barely scratch the surface.

I'm going to go out on a limb here and say M. Kraus isn't going to be
able to do that reliably, based on what we've seen from his posts.

I think M. Kraus is going to need to read the language spec, and get a
book called "Java Concurrency in Practice" by Brian Goetz. After
researching those two thoroughly he might be able to design something
workable.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html

http://jcip.net.s3-website-us-east-1.amazonaws.com/
 
M

markspace

This is broken if Thing or Collection is modifiable.

final Collection<Thing> finished = ...;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (Thing x : finished) {
x.updateTheDisplay();
}
}
});


The following would work, if you can guarantee that no Thing are being
changed while the invokeLater is running. Maybe use invokeNow instead
to make the update on the EDT synchronous.

final Collection<Thing> finished =
Collections.synchronizedCollection( new Collection() );
try { SwingUtilities.invokeNow(new Runnable() {
@Override
public void run() {
for (Thing x : finished) {
x.updateTheDisplay();
}
}
});
} catch( Exception ex ) {}

However if you have another thread besides these two that is updating
Thing asynchronously then this fails. You must also synchronize the
Thing object itself in that case.

Without a thorough understanding of threading and the Java memory model
copying by rote is fraught with error. One shouldn't be doing this sort
of thing unless one is an expert, or you're just plain going to make
broken code.
 
E

Eric Sosman

This is broken if Thing or Collection is modifiable.




The following would work, if you can guarantee that no Thing are being
changed while the invokeLater is running. Maybe use invokeNow instead
to make the update on the EDT synchronous.

I think you mean SwingUtilities.invokeAndWait(). But yes: If the
Thing or the collection of Things is being changed while other parts
of the program are trying to capture "the" state of affairs, there'll
be nothing but trouble.
final Collection<Thing> finished =
Collections.synchronizedCollection( new Collection() );
try { SwingUtilities.invokeNow(new Runnable() {
@Override
public void run() {
for (Thing x : finished) {
x.updateTheDisplay();
}
}
});
} catch( Exception ex ) {}

However if you have another thread besides these two that is updating
Thing asynchronously then this fails. You must also synchronize the
Thing object itself in that case.

I don't think using synchronizedCollection() helps here. It will
ensure that individual actions on the collection are atomic, but will
not atomize (?!) sequences of actions. In particular, you can still
get a ConcurrentModificationException.
Without a thorough understanding of threading and the Java memory model
copying by rote is fraught with error. One shouldn't be doing this sort
of thing unless one is an expert, or you're just plain going to make
broken code.

This is yet another motivation for dividing the Thing into a model
and a view thereof: It becomes easier to ensure that multiple viewers
always see the Thing in a consistent state, even if that state is
mutable and mutating.
 
M

markspace

I don't think using synchronizedCollection() helps here. It will
ensure that individual actions on the collection are atomic, but will
not atomize (?!) sequences of actions. In particular, you can still
get a ConcurrentModificationException.


Yes, if the collection is modified as the EDT is attempting to read it,
that'll happen.

I'm not sure that MVC will solve all of these issues, but a better
architecture will definitely help decompose the problem(s) into easier
pieces. I don't really like the way M. Kraus has designed his threading
code at all.
 

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

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top