<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>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:</p>
<div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
<div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#3f5fbf;">/**</span></p><p style="margin:0;"><span
style="color:#3f5fbf;"> * Adds a slow event warning whenever an event takes more than 10 </span><span
style="color:#3f5fbf;text-decoration:underline;text-decoration-color:#ff8040;text-decoration-style:wavy;">ms</span><span
style="color:#3f5fbf;"> to process. Note</span></p><p
style="margin:0;"><span style="color:#3f5fbf;"> * that time spent in nested event loops cannot be properly taken into account as time</span></p><p
style="margin:0;"><span style="color:#3f5fbf;"> * spent in nested event loops will be part of the event that triggered it giving false</span></p><p
style="margin:0;"><span style="color:#3f5fbf;"> * positives. In order for this time to be accurately reflected, the methods to enter</span></p><p
style="margin:0;"><span style="color:#3f5fbf;"> * a nested event loop in this class should be used instead of the ones in </span><span
style="color:#3f3fbf;">{@link Platform}</span><span
style="color:#3f5fbf;">.</span></p><p style="margin:0;"><span
style="color:#3f5fbf;"> *</span></p><p style="margin:0;"><span
style="color:#3f5fbf;"> * </span><span
style="color:#7f9fbf;font-weight:bold;">@param</span><span
style="color:#3f5fbf;"> scene a Scene to which to add the slow event warning detection, cannot be null</span></p><p
style="margin:0;"><span style="color:#3f5fbf;"> */</span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">public</span><span
style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">static</span><span
style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">void</span><span
style="color:#000000;"> </span><span
style="text-decoration:underline;text-decoration-style:solid;text-decoration-color:#0066cc;color:#0066cc;">addSlowEventWarning</span><span
style="color:#000000;">(Scene scene) {</span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">final</span><span
style="color:#000000;"> EventDispatcher eventDispatcher = scene.getEventDispatcher();</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> scene.setEventDispatcher(</span><span
style="color:#0000a0;font-weight:bold;">new</span><span
style="color:#000000;"> EventDispatcher() {</span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">private</span><span
style="color:#000000;"> ScheduledFuture<StackTraceElement[]> </span><span
style="color:#0000c0;">future</span><span style="color:#000000;">;</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#646464;">@Override</span></p><p style="margin:0;"><span
style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">public</span><span
style="color:#000000;"> Event dispatchEvent(Event event, EventDispatchChain tail) {</span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">if</span><span
style="color:#000000;">(</span><span style="color:#0000c0;">future</span><span
style="color:#000000;"> != </span><span
style="color:#0000a0;font-weight:bold;">null</span><span
style="color:#000000;">) {</span></p><p style="margin:0;"><span
style="color:#000000;"> </span><span
style="color:#0000c0;">future</span><span style="color:#000000;">.cancel(</span><span
style="color:#0000a0;font-weight:bold;">false</span><span
style="color:#000000;">);</span></p><p style="margin:0;"><span
style="color:#000000;"> }</span></p><p style="margin:0;"><span
style="color:#000000;"> </span></p><p style="margin:0;"><span
style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">long</span><span
style="color:#000000;"> startTime = System.</span><span
style="color:#000000;font-style:italic;">currentTimeMillis</span><span
style="color:#000000;">();</span></p><p style="margin:0;"><span
style="color:#000000;"> </span></p><p style="margin:0;"><span
style="color:#000000;"> </span><span
style="color:#0000c0;">TIME_TRACKER</span><span
style="color:#000000;">.enterNested(startTime); </span><span
style="color:#3f7f5f;">// nesting can happen in two ways, an event triggering another event, or when a nested event loop is entered</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> Event returnedEvent = eventDispatcher.dispatchEvent(event, tail);</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">long</span><span
style="color:#000000;"> endTime = System.</span><span
style="color:#000000;font-style:italic;">currentTimeMillis</span><span
style="color:#000000;">();</span></p><p style="margin:0;"><span
style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">long</span><span
style="color:#000000;"> timeSpentInNested = </span><span
style="color:#0000c0;">TIME_TRACKER</span><span
style="color:#000000;">.exitNested(endTime);</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">if</span><span
style="color:#000000;">(timeSpentInNested > 10) {</span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000a0;font-weight:bold;">long</span><span
style="color:#000000;"> total = endTime - startTime;</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#0000c0;">LOGGER</span><span style="color:#000000;">.warning(</span><span
style="color:#2a00ff;">"Slow Event (self/total: "</span><span
style="color:#000000;"> + timeSpentInNested + </span><span
style="color:#2a00ff;">"/"</span><span style="color:#000000;"> + total + </span><span
style="color:#2a00ff;">" ms @ level "</span><span
style="color:#000000;"> + </span><span style="color:#0000c0;">TIME_TRACKER</span><span
style="color:#000000;">.getCurrentLevel() + </span><span
style="color:#2a00ff;">"): "</span><span style="color:#000000;"> + event);</span></p><p
style="margin:0;"><span style="color:#000000;"> }</span></p><p
style="margin:0;"><span style="color:#000000;"> </span></p><p
style="margin:0;"><span style="color:#000000;"> </span><span
style="color:#7f0055;font-weight:bold;">return</span><span
style="color:#000000;"> returnedEvent;</span></p><p
style="margin:0;"><span style="color:#000000;"> }</span></p><p
style="margin:0;"><span style="color:#000000;"> });</span></p><p
style="margin:0;"><span style="color:#000000;"> }</span></p><p
style="margin:0;"><span style="color:#000000;">
</span></p><p style="margin:0;"><span style="color:#000000;">--John
</span></p></div>
</div>
<p></p>
<div class="moz-cite-prefix">On 05/08/2024 17:17, Thiago Milczarek
Sayão wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAAP_wumFGfLeXc3yyt9NcVrAvbSH-MaJdK2rauYuHoiYtTFAiw@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">
<div dir="ltr">Hi,
<div><br>
</div>
<div>Interesting idea. We have this problem specially when
Junior developers touch the code.</div>
<div><br>
</div>
<div>The other way around would be nice too - if some I/O task
executes on the FX thread.</div>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>-- Thiago.</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">Em seg., 5 de ago. de 2024
às 11:59, Kevin Rushforth <<a
href="mailto:kevin.rushforth@oracle.com"
moz-do-not-send="true" class="moz-txt-link-freetext">kevin.rushforth@oracle.com</a>>
escreveu:<br>
</div>
<blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
<blockquote type="cite">Wouldn't it be better to implement
this check in assert to avoid any impact in production?</blockquote>
<br>
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.<br>
<br>
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.<br>
<br>
The things to consider would be:<br>
<br>
1. What is the performance hit of doing this check on the
setting of every property?<br>
2. What is the effect on bound properties?<br>
3. How intrusive is it in the code?<br>
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?<br>
<br>
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.<br>
<br>
-- Kevin<br>
<br>
<br>
<div>On 8/4/2024 8:40 PM, quizynox wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Hello,<br>
<br>
Wouldn't it be better to implement this check in
assert to avoid any impact in production?</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">пн, 5 авг. 2024 г. в
03:30, John Hendrikx <<a
href="mailto:john.hendrikx@gmail.com"
target="_blank" moz-do-not-send="true"
class="moz-txt-link-freetext">john.hendrikx@gmail.com</a>>:<br>
</div>
<blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi
list,<br>
<br>
I know of quite some bugs and users that have been
bitten by the <br>
threading model used by JavaFX. Basically, anything
directly or <br>
indirectly linked to an active Scene must be
accessed on the FX thread. <br>
However, as FX also allows manipulating nodes and
properties before <br>
they're displayed, there can be no "hard" check
everywhere to ensure we <br>
are on the FX thread (specifically, in properties).<br>
<br>
Now, I think this situation is annoying, as a simple
mistake where a <br>
Platform.runLater wrapper was forgotten usually
results in programs <br>
operating mostly flawlessly, but then fail in
mysterious and random and <br>
hard to reproduce ways. The blame is often put on
FX as the resulting <br>
exceptions will almost never show the user code
which was the actual <br>
culprit. It can result in FX being perceived as
unstable or buggy.<br>
<br>
So I've been thinking if there isn't something we
can do to detect these <br>
bugs originating from user code much earlier,
similar to the <br>
`ConcurrentModificationException` the collection
classes do when <br>
accessed in nested or concurrent contexts.<br>
<br>
I think it may be possible to have properties check
whether they're part <br>
of an active scene without too much of an
performance impact, possibly <br>
even behind a switch. It would work like this:<br>
<br>
Properties involved with Nodes will have an
associated bean instance <br>
(`getBean`). This is an object, but we could check
here if this <br>
instance implements an interface:<br>
<br>
if (getBean() instanceof MayBePartOfSceneGraph
x) {<br>
if (x.isPartOfActiveScene() &&
!isOnFxThread()) {<br>
throw new
IllegalStateException("Property must only be <br>
used from the FX Application Thread");<br>
}<br>
}<br>
<br>
This check could be done on every set of the
property, and potentially <br>
on every get as well. It should be relatively
cheap, but will expose <br>
problematic code patterns at a much earlier stage.
There's a chance <br>
that this will "break" some programs that seemed to
be behaving <br>
correctly as well, so we may want to put it behind a
switch until such <br>
programs (or libraries) can be fixed.<br>
<br>
What do you all think?<br>
<br>
--John<br>
<br>
(*) Names of methods/interfaces are only used for
illustration purposes, <br>
we can think of good names if this moves forward.<br>
<br>
</blockquote>
</div>
</blockquote>
<br>
</div>
</blockquote>
</div>
</div>
</blockquote>
</body>
</html>