Guice + Swing + SwingWorker + background threads

298 views
Skip to first unread message

caru

unread,
Jun 23, 2011, 12:11:58 AM6/23/11
to google...@googlegroups.com
Hi all,
I am configuring the GUI by instantiating the injector in the "invokeLater" method, to make sure all Swing components get instantiated in the EDT.
The issue is I must define some SwingWorkers which need injection of both a Swing component and a background thread object (singleton) , to be used in the doInBackground() method.
Since singletons are instantiated eagerly (at least in production stage), the solution I figured out was to use a different injector to instantiate such a singleton, which is called in the main method, to make sure the singleton actually get instantiated in a thread which is not EDT.

I'd like to have a constructor such as:
@Inject MySwingWorker(JPanel panel, MyBackgroundThreadInterface massiveTaskPerformer) {...}

But this won't work, as MySwingWorker and JPanel are created by the Swing injector and the second parameter is provided by a different injector...

To wrap up, I am pretty sure I am overcomplicating the problem... without actually solving it :) Do you know a good way to solve this?


Aekold

unread,
Jun 24, 2011, 3:03:58 AM6/24/11
to google-guice
SwingWorker is supposed to be constructed in EDT too, and it will go
to background thread pool queue after invoking execute() method. So
you do not need to create different injectors.
If your background SwingWorker wants to do something with swing
components - there is process(List<V> chunks) method, and you have to
design your implementation to do all component processing there.

PS: that's none of my business, but as for me if you have only one
background thread - SwingWorker declares too many rules. You could
create your own implementation with basic synchronization primitives,
make it optimized for your concrete task, without creating that 10-
threads pool and collecting unwanted intermediate results into
accumulative runnables as SwingWorker does.

caru

unread,
Jun 25, 2011, 12:02:32 AM6/25/11
to google...@googlegroups.com
Thank you for the help!

I resolved that by having MyBackgorundThreadInterface implementation instantiated by guice inside the EDT, since it is singleton and as such it is instantiated eagerly. Then, when I call its methods inside MySwingWorker.doInBackground(), as you say, such methods actually run inside the SwingWorker thread (I verified it with AOP interceptors, what a good stuff they are), hence without interfering with the EDT.

Still, I am not sure whether instantiating MyBackgroundThreadInterface inside the EDT is a good idea... I guess that it is not that bad, if you make sure its methods will never be called inside the EDT...

Aekold

unread,
Jun 27, 2011, 2:07:44 PM6/27/11
to google-guice
Well, here is the world as I see it:
1) all of the UI tookits I've ever heard about there is "single thread
rule". In case of Swing this thread is named EDT. They could make it
multithreaded, but "you should allow UI programmer to be dumb ignorant
moron, he is not supposed to know about threads and synchronization".
I don't mind all that stuff about EDT, but the reason of it is
completely wrong to me.
2) eventually that led to concurrency bugs, which are extremely hard
to reproduce. So they established simple rule - "one thread to rule
them all", "thou shall not touch JComponent and it's heirs outside of
EDT". If you worked with Swing starting with Java 1.4 - that rule was
not established at that time, it appeared some time before java 6
release, while source code is basically the same.
3) when everybody started doing everything in EDT - it led to UI
freezing (or graying out) because EDT was busy with some time
consuming tasks and was not able to iterate over "dirty regions" to
repaint them. So they've made SwingWorker to simplify backgrounding of
time-consuming tasks. By time consuming in most cases we mean IO
operations and remote invocation, which are unpredictable, while it's
pretty safe to execute any code while it works only with reasonable
amount of CPU time and RAM. All those methods in SwingWorker are far
from lightweight, for example publish() is gathering all that data in
so called AccumulativeRunnable, collecting all that data into
ArrayList, and then that AccumulativeRunnable is submitted to EDT and
you'll get that list in publish(). Or creation of real Thread instance
in execute() method...

So as for me - it's completely correct to initialize GUICE and
construct SwingWorker inside EDT, as long as your UI is not frozen by
those operations. Just try to construct and show JFileChooser and see
for how long it will freeze your UI before actually showing itself and
I am almost sure that you will be completely happy with your solution.

Tim Peierls

unread,
Jun 27, 2011, 3:45:08 PM6/27/11
to google...@googlegroups.com
On Fri, Jun 24, 2011 at 3:03 AM, Aekold <helb...@gmail.com> wrote:
SwingWorker is supposed to be constructed in EDT too, 

Really? I can't find anything that supports that, and a sentence in the javadoc, "Often, the Current thread is the Event Dispatch Thread," implies that sometimes it isn't.

 
So you do not need to create different injectors.

Agreed.

If you really want to inject Swing components and ensure they are constructed in the EDT, consider a custom Scope.


--tim

Aekold

unread,
Jun 28, 2011, 1:17:21 AM6/28/11
to google-guice
On Jun 27, 10:45 pm, Tim Peierls <t...@peierls.net> wrote:
> On Fri, Jun 24, 2011 at 3:03 AM, Aekold <helbr...@gmail.com> wrote:
> > SwingWorker is supposed to be constructed in EDT too,
>
> Really? I can't find anything that supports that, and a sentence in the
> javadoc<http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker....>,
> "Often, the Current thread is the Event Dispatch Thread," implies that
> sometimes it isn't.

Yes, that's not a rule of course. I mean that official SwingWorker
usage guide
http://download.oracle.com/javase/tutorial/uiswing/concurrency/interim.html
is showing this example
http://download.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java
so it's obvious that SwingWorker construction in EDT is not a problem
and is not something to avoid by crippling structure of your
application. Though it's obvious it's construction should not be
heavy, because main purpose of SwingWorker is to return control back
to EDT, so all heavy operations you can move into doInBackground().

Craig Day

unread,
Jul 27, 2011, 9:04:30 PM7/27/11
to google...@googlegroups.com
Nice. Gotta love Guice.
Reply all
Reply to author
Forward
0 new messages