I have some legacy code to spruce up, and it breaks one of the cardinal
rules of swing: it updates the UI with worker threads (not the EDT).
Finding all of the potential culprits is easy, but there are hundreds of
cases which could be problematic, and the vast majority are fine. It is
quite difficult to determine via inspection whether or not a specific
worker thread will cause problems because dependencies back to the UI
are typically routed through at least one interface, one or more
abstract classes and a chain of one or more listeners (business objects
expose a generic property change event, and all manner of things
register for notifications). How can I figure out which threads have a
transitive dependency back to some UI object? I could easily name worker
threads, but the problems typically manifest themselves on the EDT in
the various paint methods. Is there any way I could instrument the code
so that in development, I could throw an exception any time a component
is touched by a thread other than the EDT?
--
Shane
|
|
0
|
|
|
|
Reply
|
i
|
8/1/2008 7:57:58 PM |
|
i.dont.need@any.more.email writes:
> I have some legacy code to spruce up, and it breaks one of the
> cardinal rules of swing: it updates the UI with worker threads (not
> the EDT). Finding all of the potential culprits is easy, but there are
> hundreds of cases which could be problematic, and the vast majority
> are fine. It is quite difficult to determine via inspection whether or
> not a specific worker thread will cause problems ... How can I figure
> out which threads have a transitive dependency back to some UI object?
Well, what sorts of actions does the application take in connection with
the EDT?
If you know what types of manipulation are being done, then you may be
able to instrument just the places where those sorts of things happen,
such as creating new windows, updating the state of controls, etc.
You could insert something like:
assert SwingUtilities.isEventDispatchThread();
in the places where UI elements are created, modified or manipulated and
see where any errors pop up. You would need to make sure you enabled
assertion checking for the development phase.
> Is there any way I could instrument the code
> so that in development, I could throw an exception any time a component
> is touched by a thread other than the EDT?
I was working on one project where they had some such instrumentation,
which threw an exception if it thought something was doing GUI work on a
thread other than the EDT. But I don't recall what was done to achieve
this. But there is something out there.
--
Thomas A. Russ, USC/Information Sciences Institute
|
|
0
|
|
|
|
Reply
|
tar
|
8/1/2008 9:04:16 PM
|
|
i.dont.need@any.more.email wrote:
>
> I have some legacy code to spruce up, and it breaks one of the cardinal
> rules of swing: it updates the UI with worker threads (not the EDT).
> Finding all of the potential culprits is easy, but there are hundreds of
> cases which could be problematic, and the vast majority are fine. It is
> quite difficult to determine via inspection whether or not a specific
> worker thread will cause problems because dependencies back to the UI
> are typically routed through at least one interface, one or more
> abstract classes and a chain of one or more listeners (business objects
> expose a generic property change event, and all manner of things
> register for notifications). How can I figure out which threads have a
> transitive dependency back to some UI object? I could easily name worker
> threads, but the problems typically manifest themselves on the EDT in
> the various paint methods. Is there any way I could instrument the code
> so that in development, I could throw an exception any time a component
> is touched by a thread other than the EDT?
>
> --
> Shane
You appear to contradict yourself so it is difficult to understand why
you can't just put the Swing component method calls on the EDT if the
culprits are easy to find.
That said, most Listeners are going to be called on the EDT so I
wouldn't worry about that code.
If you want to trap calls to the paintComponent() method that aren't on
the EDT, use EventQueue.isDispatchThread() and throw an exception if it
is false. The problem I see with that is that calls to methods that
later call repaint() will not be found.
--
Knute Johnson
email s/nospam/knute2008/
--
Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
------->>>>>>http://www.NewsDemon.com<<<<<<------
Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
|
|
0
|
|
|
|
Reply
|
Knute
|
8/1/2008 9:29:11 PM
|
|
Knute Johnson wrote:
> i.dont.need@any.more.email wrote:
>>
>> I have some legacy code to spruce up, and it breaks one of the
>> cardinal rules of swing: it updates the UI with worker threads (not
>> the EDT). Finding all of the potential culprits is easy, but there are
>> hundreds of cases which could be problematic, and the vast majority
>> are fine. It is quite difficult to determine via inspection whether or
>> not a specific worker thread will cause problems because dependencies
>> back to the UI are typically routed through at least one interface,
>> one or more abstract classes and a chain of one or more listeners
>> (business objects expose a generic property change event, and all
>> manner of things register for notifications). How can I figure out
>> which threads have a transitive dependency back to some UI object? I
>> could easily name worker threads, but the problems typically manifest
>> themselves on the EDT in the various paint methods. Is there any way I
>> could instrument the code so that in development, I could throw an
>> exception any time a component is touched by a thread other than the EDT?
>>
>> --
>> Shane
>
> You appear to contradict yourself so it is difficult to understand why
> you can't just put the Swing component method calls on the EDT if the
> culprits are easy to find.
The ones that are easy to find are: "potential culprits". A simple 'find
usages' on thread.start() and runnable.run() will easily locate all
worker threads. The issue is which ones of the hundreds found are
problematic.
> That said, most Listeners are going to be called on the EDT so I
> wouldn't worry about that code.
Listeners appear to be the biggest culprits. That is, things which
listen to the business objects which in turn transitively update the UI.
The business objects are manipulated via worker threads, and their
dependencies cause the problems.
> If you want to trap calls to the paintComponent() method that aren't on
> the EDT, use EventQueue.isDispatchThread() and throw an exception if it
> is false. The problem I see with that is that calls to methods that
> later call repaint() will not be found.
How do I inject this code into JComponent? There are thousands of swing
instances in the application which might be affected, I need to sort out
which ones actually are, then trace back to the problematic worker
thread and separate the background process from the UI.
--
Shane
|
|
0
|
|
|
|
Reply
|
i
|
8/2/2008 4:56:34 AM
|
|
Thomas A. Russ wrote:
> i.dont.need@any.more.email writes:
>
>> I have some legacy code to spruce up, and it breaks one of the
>> cardinal rules of swing: it updates the UI with worker threads (not
>> the EDT). Finding all of the potential culprits is easy, but there are
>> hundreds of cases which could be problematic, and the vast majority
>> are fine. It is quite difficult to determine via inspection whether or
>> not a specific worker thread will cause problems ... How can I figure
>> out which threads have a transitive dependency back to some UI object?
>
> Well, what sorts of actions does the application take in connection with
> the EDT?
I'm not altogether sure what you're asking here.
> If you know what types of manipulation are being done, then you may be
> able to instrument just the places where those sorts of things happen,
> such as creating new windows, updating the state of controls, etc.
Hmm... I kinda get where you're going, but a priori, I don't really know
what is causing the problem. Updating the state of controls is
definitely an issue, but which controls? There are boatloads of
possibilities. One place that seems to have high frequency is
DefaultTableColumnModel.getColumn(int) which gets called from
BasicTableUI.paintCells. I guess any worker threads pulling out data
from the db which gets put into to tables is a place to start here. It's
quite a manual approach, but better than none.
> assert SwingUtilities.isEventDispatchThread();
I like the simplicity of this, I just wish I could automate it for all
swing classes rather than have to hunt down all code which interacts
with the classes I happen to be targeting.
>> Is there any way I could instrument the code
>> so that in development, I could throw an exception any time a component
>> is touched by a thread other than the EDT?
>
> I was working on one project where they had some such instrumentation,
> which threw an exception if it thought something was doing GUI work on a
> thread other than the EDT. But I don't recall what was done to achieve
> this. But there is something out there.
Do you recall any names of classes or tools or techniques you used?
Googling things related to the EDT or worker threads turns up heaps of
stuff which is unrelated.
Thanks.
--
Shane
|
|
0
|
|
|
|
Reply
|
i
|
8/2/2008 5:11:36 AM
|
|
i.dont.need@any.more.email wrote:
> Knute Johnson wrote:
>> i.dont.need@any.more.email wrote:
>>>
>>> I have some legacy code to spruce up, and it breaks one of the
>>> cardinal rules of swing: it updates the UI with worker threads (not
>>> the EDT).
>
>> If you want to trap calls to the paintComponent() method that aren't
>> on the EDT, use EventQueue.isDispatchThread() and throw an exception
>> if it is false. The problem I see with that is that calls to methods
>> that later call repaint() will not be found.
>
> How do I inject this code into JComponent? There are thousands of swing
> instances in the application which might be affected, I need to sort out
> which ones actually are, then trace back to the problematic worker
> thread and separate the background process from the UI.
>
I use ThreadCheckingRepaintManager from
http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
--
RGB
|
|
0
|
|
|
|
Reply
|
RedGrittyBrick
|
8/2/2008 10:50:57 AM
|
|
RedGrittyBrick wrote:
> i.dont.need@any.more.email wrote:
>> Knute Johnson wrote:
>>> i.dont.need@any.more.email wrote:
>>>>
>>>> I have some legacy code to spruce up, and it breaks one of the
>>>> cardinal rules of swing: it updates the UI with worker threads (not
>>>> the EDT).
>>
>>> If you want to trap calls to the paintComponent() method that aren't
>>> on the EDT, use EventQueue.isDispatchThread() and throw an exception
>>> if it is false. The problem I see with that is that calls to methods
>>> that later call repaint() will not be found.
>>
>> How do I inject this code into JComponent? There are thousands of
>> swing instances in the application which might be affected, I need to
>> sort out which ones actually are, then trace back to the problematic
>> worker thread and separate the background process from the UI.
>>
>
> I use ThreadCheckingRepaintManager from
> http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
>
>
That's a very handy tool. I think it will catch a lot of his problems
with very little effort.
--
Knute Johnson
email s/nospam/knute2008/
--
Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
------->>>>>>http://www.NewsDemon.com<<<<<<------
Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
|
|
0
|
|
|
|
Reply
|
Knute
|
8/2/2008 4:47:09 PM
|
|
Knute Johnson wrote:
> RedGrittyBrick wrote:
>>
>> I use ThreadCheckingRepaintManager from
>> http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
>
> That's a very handy tool. I think it will catch a lot of his problems
> with very little effort.
Indeed! Thanks
--
Shane
|
|
0
|
|
|
|
Reply
|
i
|
8/3/2008 6:47:10 PM
|
|
On 01 Aug 2008 14:04:16 -0700, tar@sevak.isi.edu (Thomas A. Russ)
wrote, quoted or indirectly quoted someone who said :
> assert SwingUtilities.isEventDispatchThread();
In Forth it was fairly easy to insert your own code at the head of any
existing method to help debug. I think there is a feature in Java now
that lets you pull off something similar.
Someone mentioned it recently when I asked about ways to tell if a
class is already loaded without actually triggering a load.
If you could instrument some of the methods of JComponent, you could
put your assertions there.
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
|
|
0
|
|
|
|
Reply
|
Roedy
|
8/10/2008 8:51:45 PM
|
|
<i.dont.need@any.more.email> wrote in message
news:aVJkk.50144$nD.30868@pd7urf1no...
>
> ... Is there any way I could instrument the code so that in development, I
> could throw an exception any time a component is touched by a thread other
> than the EDT?
I had this need and ended up using AspectJ to
inject a test before every gui call, using the
following aspect:
aspect ThreadChecker {
pointcut guiCall():
(call(* java.awt..*(..)) || call(* javax.swing..*(..))
|| call(java.awt..*.new(..)) || call(javax.swing..*.new(..)))
&& !call(* clone()) && !call(void
SwingUtilities.invokeLater(Runnable))
&& !call(boolean SwingUtilities.isEventDispatchThread())
&& !call(* javax.swing.text.html.HTMLDocument..*(..));
before(): guiCall() && !within(ThreadChecker) {
if (!SwingUtilities.isEventDispatchThread()) {
System.err.println("Bad gui call:");
System.err.println(thisJoinPoint.getSourceLocation());
System.err.println(thisJoinPoint.getSignature());
System.err.println();
}
}
}
You'll probably need some tinkering depending on the
Java version you target and which other thread-safe
gui methods you call (repaint() isn't in the above for
example, but I never call it from outside the EDT and
don't expect to ever need to do so).
It's pretty easy to set up a build to inject that test into
a jar file and merge in the ThreadChecker class and
the AspectJ runtime classes.
|
|
0
|
|
|
|
Reply
|
Larry
|
8/11/2008 11:04:10 AM
|
|
Larry A Barowski wrote:
>
> I had this need and ended up using AspectJ to
> inject a test before every gui call, using the
> following aspect:
Thanks, AOP and bytecode injection were the only possibilities that
sprang to mind, but I had never tried either. At the moment, my
attention has been diverted to another project, but the
ThreadCheckingRepaintManager class mentioned earlier has already given
me something to chew on. When I get back to this issue, I'll give your
aspect a try too.
--
Shane
>
> aspect ThreadChecker {
> pointcut guiCall():
> (call(* java.awt..*(..)) || call(* javax.swing..*(..))
> || call(java.awt..*.new(..)) || call(javax.swing..*.new(..)))
> && !call(* clone()) && !call(void
> SwingUtilities.invokeLater(Runnable))
> && !call(boolean SwingUtilities.isEventDispatchThread())
> && !call(* javax.swing.text.html.HTMLDocument..*(..));
>
> before(): guiCall() && !within(ThreadChecker) {
> if (!SwingUtilities.isEventDispatchThread()) {
> System.err.println("Bad gui call:");
> System.err.println(thisJoinPoint.getSourceLocation());
> System.err.println(thisJoinPoint.getSignature());
> System.err.println();
> }
> }
> }
>
> You'll probably need some tinkering depending on the
> Java version you target and which other thread-safe
> gui methods you call (repaint() isn't in the above for
> example, but I never call it from outside the EDT and
> don't expect to ever need to do so).
>
> It's pretty easy to set up a build to inject that test into
> a jar file and merge in the ThreadChecker class and
> the AspectJ runtime classes.
>
>
>
|
|
0
|
|
|
|
Reply
|
i
|
8/11/2008 6:33:36 PM
|
|
<i.dont.need@any.more.email> wrote in message
news:4C%nk.126079$kx.82177@pd7urf3no...
> Thanks, AOP and bytecode injection were the only possibilities that sprang
> to mind, but I had never tried either. At the moment, my attention has
> been diverted to another project, but the ThreadCheckingRepaintManager
> class mentioned earlier has already given me something to chew on.
That is simple enough, but it will catch fewer problems than a
check before every gui call.
> When I get back to this issue, I'll give your aspect a try too.
It has worked out great for me. I was converting a debugger
from EDT-only to having a separate, dedicated debugger
thread. So in addition to checking that gui calls only come
from the EDT, I also needed to verify that all JDI calls
come from the debugger thread. The tests also turned up a
few EDT violations in the software that were totally
unrelated to the debugger.
|
|
0
|
|
|
|
Reply
|
Larry
|
8/11/2008 7:12:58 PM
|
|
Roedy Green a �crit :
> On 01 Aug 2008 14:04:16 -0700, tar@sevak.isi.edu (Thomas A. Russ)
> wrote, quoted or indirectly quoted someone who said :
>
>
>> assert SwingUtilities.isEventDispatchThread();
>
>
> In Forth it was fairly easy to insert your own code at the head of any
> existing method to help debug. I think there is a feature in Java now
> that lets you pull off something similar.
>
=> see AspectJ ( aspectj.eclipse.org) and AOP programming
|
|
0
|
|
|
|
Reply
|
jlp
|
8/17/2008 11:32:54 AM
|
|
|
12 Replies
202 Views
(page loaded in 0.013 seconds)
|