Detecting threading problems faster

John Hendrikx john.hendrikx at gmail.com
Wed Aug 7 18:55:09 UTC 2024


For detecting long running tasks on the FX thread, there are some other 
options which you can do as a user (but perhaps we can support it 
directly within FX).  I use this kind of code to detect long running 
things on the FX thread:

/**

* Adds a slow event warning whenever an event takes more than 10 msto 
process. Note

* that time spent in nested event loops cannot be properly taken into 
account as time

* spent in nested event loops will be part of the event that triggered 
it giving false

* positives. In order for this time to be accurately reflected, the 
methods to enter

* a nested event loop in this class should be used instead of the ones 
in {@link Platform}.

*

* @paramscene a Scene to which to add the slow event warning detection, 
cannot be null

*/

publicstaticvoidaddSlowEventWarning(Scene scene) {

finalEventDispatcher eventDispatcher = scene.getEventDispatcher();

scene.setEventDispatcher(newEventDispatcher() {

privateScheduledFuture<StackTraceElement[]> future;

@Override

publicEvent dispatchEvent(Event event, EventDispatchChain tail) {

if(future!= null) {

future.cancel(false);

}

longstartTime = System.currentTimeMillis();

TIME_TRACKER.enterNested(startTime); // nesting can happen in two ways, 
an event triggering another event, or when a nested event loop is entered

Event returnedEvent = eventDispatcher.dispatchEvent(event, tail);

longendTime = System.currentTimeMillis();

longtimeSpentInNested = TIME_TRACKER.exitNested(endTime);

if(timeSpentInNested > 10) {

longtotal = endTime - startTime;

LOGGER.warning("Slow Event (self/total: "+ timeSpentInNested + "/"+ 
total + " ms @ level "+ TIME_TRACKER.getCurrentLevel() + "): "+ event);

}

returnreturnedEvent;

}

});

}

--John

On 05/08/2024 17:17, Thiago Milczarek Sayão wrote:
> Hi,
>
> Interesting idea. We have this problem specially when Junior 
> developers touch the code.
>
> The other way around would be nice too - if some I/O task executes on 
> the FX thread.
>
> This can make the OS think the application hanged and offer to kill 
> it, since it won't respond to "pings". And I/O tasks processing time 
> may vary between installations. Also causes "white screens" since it 
> blocks painting.
>
> -- Thiago.
>
> Em seg., 5 de ago. de 2024 às 11:59, Kevin Rushforth 
> <kevin.rushforth at oracle.com> escreveu:
>
>>     Wouldn't it be better to implement this check in assert to avoid
>>     any impact in production?
>
>     No. Using an assert in a case like this is an anti-pattern. A call
>     to assert in a library such as JavaFX is only appropriate for
>     checking an invariant in internal logic. If we are going to go
>     down this route of doing a thread check when mutating properties
>     of "live" nodes, we will throw the same IllegalStateException that
>     is currently thrown by some methods on Stage and Scene.
>
>     As for the proposal itself, adding this check is an interesting
>     idea. We considered doing this back in the JDK 7 (JavaFX 2) time
>     frame, but decided not to pursue it then. I think the idea is
>     worth further discussion. I would limit any thread checking to
>     setting the property. It would be too restrictive (and largely
>     unnecessary) to prevent reading a property from the application
>     thread.
>
>     The things to consider would be:
>
>     1. What is the performance hit of doing this check on the setting
>     of every property?
>     2. What is the effect on bound properties?
>     3. How intrusive is it in the code?
>     4. Should we add a property to enable / disable the thread check,
>     possibly a three- or four-valued property
>     (allow|warn|debug?|deny), as was recently done in JEP 471 for
>     sun.misc.Unsafe memory access methods. If so, what should the
>     default be?
>
>     My quick take is that if this can be done in a minimally intrusive
>     manner with low overhead, we should consider pursing this. As for
>     4, my preference would be to add a three- or four-valued system
>     property to control the check, with "warn" as the default
>     initially, changing the default to "disallow" in a subsequent
>     version. This would, of course, require a lot of testing.
>
>     -- Kevin
>
>
>     On 8/4/2024 8:40 PM, quizynox wrote:
>>     Hello,
>>
>>     Wouldn't it be better to implement this check in assert to avoid
>>     any impact in production?
>>
>>     пн, 5 авг. 2024 г. в 03:30, John Hendrikx <john.hendrikx at gmail.com>:
>>
>>         Hi list,
>>
>>         I know of quite some bugs and users that have been bitten by the
>>         threading model used by JavaFX.  Basically, anything directly or
>>         indirectly linked to an active Scene must be accessed on the
>>         FX thread.
>>         However, as FX also allows manipulating nodes and properties
>>         before
>>         they're displayed, there can be no "hard" check everywhere to
>>         ensure we
>>         are on the FX thread (specifically, in properties).
>>
>>         Now, I think this situation is annoying, as a simple mistake
>>         where a
>>         Platform.runLater wrapper was forgotten usually results in
>>         programs
>>         operating mostly flawlessly, but then fail in mysterious and
>>         random and
>>         hard to reproduce ways.  The blame is often put on FX as the
>>         resulting
>>         exceptions will almost never show the user code which was the
>>         actual
>>         culprit.  It can result in FX being perceived as unstable or
>>         buggy.
>>
>>         So I've been thinking if there isn't something we can do to
>>         detect these
>>         bugs originating from user code much earlier, similar to the
>>         `ConcurrentModificationException` the collection classes do when
>>         accessed in nested or concurrent contexts.
>>
>>         I think it may be possible to have properties check whether
>>         they're part
>>         of an active scene without too much of an performance impact,
>>         possibly
>>         even behind a switch. It would work like this:
>>
>>         Properties involved with Nodes will have an associated bean
>>         instance
>>         (`getBean`).  This is an object, but we could check here if this
>>         instance implements an interface:
>>
>>               if (getBean() instanceof MayBePartOfSceneGraph x) {
>>                     if (x.isPartOfActiveScene() && !isOnFxThread()) {
>>                          throw new IllegalStateException("Property
>>         must only be
>>         used from the FX Application Thread");
>>                     }
>>               }
>>
>>         This check could be done on every set of the property, and
>>         potentially
>>         on every get as well.  It should be relatively cheap, but
>>         will expose
>>         problematic code patterns at a much earlier stage. There's a
>>         chance
>>         that this will "break" some programs that seemed to be behaving
>>         correctly as well, so we may want to put it behind a switch
>>         until such
>>         programs (or libraries) can be fixed.
>>
>>         What do you all think?
>>
>>         --John
>>
>>         (*) Names of methods/interfaces are only used for
>>         illustration purposes,
>>         we can think of good names if this moves forward.
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20240807/ffd19ecf/attachment-0001.htm>


More information about the openjfx-dev mailing list