<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    Thank you to Jurgen for raising the question and to Nir, John, and
    Michael for evaluating it.<br>
    <br>
    I conclude that there is insufficient motivation to revert the
    change in behavior implemented by JDK-8159048 to allow calling the
    play/pause/stop methods of Animation on a background thread. Doing
    so without making it fully multi-thread-safe would be asking for
    problems, and making it fully multi-thread-safe would be a fair bit
    of work to do it right without a clear benefit.<br>
    <br>
    We will proceed with the current approach and let JDK-8159048 stand.
    Further, we will proceed with
    <a class="moz-txt-link-freetext" href="https://bugs.openjdk.org/browse/JDK-8324219">https://bugs.openjdk.org/browse/JDK-8324219</a> which is under review in
    <a class="moz-txt-link-freetext" href="https://github.com/openjdk/jfx/pull/1342">https://github.com/openjdk/jfx/pull/1342</a><br>
    <br>
    -- Kevin<br>
    <br>
    <div class="moz-cite-prefix">On 1/24/2024 12:30 AM, Nir Lisker
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CA+0ynh88b4=5A5DHF__xMaS0wPvE7HyhMFoqeAPV7pFCHBGgYQ@mail.gmail.com">
      
      <div dir="auto">After playing around with the code sample, I think
        that this is not the right way to use the animation. The reason
        is that there is no point in starting the animation before the
        control is attached to the scenegraph, or even made visible. A
        small refactoring where, e.g., the controller class exposes a
        method to start the animation in onSucceeded or just calls it on
        the FX thread is enough. I never start an animation as part of
        the construction because it's not the right time. John suggested
        tying the lifecycle of the animation to the showing of the node,
        which also solves the problem. 
        <div dir="auto"><br>
        </div>
        <div dir="auto">There are animations like PauseTransition or
          other non-interfering Timelines that could reasonably be run
          on a background thread. Or maybe just on an unconnected
          control. This could be a reason to not limit animation methods
          to the FX thread at the expense of possible user errors, but
          document the pitfall.</div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">I don't see a good use case for modifying
          controls in a background thread while still interacting with
          the scenegraph, hence for adding multithread support. </div>
        <div dir="auto"><br>
        </div>
        <div dir="auto">- Nir</div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Jan 22, 2024, 12:59
          Jurgen Doll <<a href="mailto:javafx@ivoryemr.co.za" moz-do-not-send="true" class="moz-txt-link-freetext">javafx@ivoryemr.co.za</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
          <div>
            <div><big>Here's an example as requested by Nir:</big></div>
            <div><big><br>
              </big></div>
            <div><span style="color:#7f0055;font-weight:bold">public</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">class</span><span style="color:#000000"> FxTimeLineTest </span><span style="color:#7f0055;font-weight:bold">extends</span><span style="color:#000000"> Application</span></div>
            <div>
              <div style="background-color:#ffffff;padding:0px 2px 0px 2px">
                <div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><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">private</span><span style="color:#000000"> BorderPane </span><span style="color:#0000c0">bp</span><span style="color:#000000"> = </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> BorderPane( </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> Label(</span><span style="color:#2a00ff">"Loading"</span><span style="color:#000000">) );</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">    </span><span style="color:#7f0055;font-weight:bold">public</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">static</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">void</span><span style="color:#000000"> main( String[] </span><span style="color:#6a3e3e">args</span><span style="color:#000000"> ) {</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#000000;font-style:italic">launch</span><span style="color:#000000">( FxTimeLineTest.</span><span style="color:#7f0055;font-weight:bold">class</span><span style="color:#000000">, </span><span style="color:#6a3e3e">args</span><span style="color:#000000"> );</span></p><p style="margin:0"><span style="color:#000000">    }</span></p><p style="margin:0">
</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:#7f0055;font-weight:bold">public</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">void</span><span style="color:#000000"> start( Stage </span><span style="color:#6a3e3e">primaryStage</span><span style="color:#000000"> ) </span><span style="color:#7f0055;font-weight:bold">throws</span><span style="color:#000000"> Exception {</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> Thread( </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> LoadScene() ).start();</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#6a3e3e">primaryStage</span><span style="color:#000000">.setScene( </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> Scene( </span><span style="color:#0000c0">bp</span><span style="color:#000000">, 300, 200 ) );</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#6a3e3e">primaryStage</span><span style="color:#000000">.setTitle( </span><span style="color:#2a00ff">"Memory Usage"</span><span style="color:#000000"> );</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#6a3e3e">primaryStage</span><span style="color:#000000">.show();</span></p><p style="margin:0"><span style="color:#000000">    }</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">    </span><span style="color:#7f0055;font-weight:bold">private</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">class</span><span style="color:#000000"> LoadScene </span><span style="color:#7f0055;font-weight:bold">extends</span><span style="color:#000000"> Task<Parent> {</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#646464">@Override</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">protected</span><span style="color:#000000"> Parent call() </span><span style="color:#7f0055;font-weight:bold">throws</span><span style="color:#000000"> Exception {</span></p><p style="margin:0"><span style="color:#000000">            Parent </span><span style="color:#6a3e3e">p</span><span style="color:#000000"> = FXMLLoader.</span><span style="color:#000000;font-style:italic">load</span><span style="color:#000000">( getClass().getResource(</span><span style="color:#2a00ff">"TestView.fxml"</span><span style="color:#000000">) );</span></p><p style="margin:0"><span style="color:#000000">            Thread.</span><span style="color:#000000;font-style:italic">sleep</span><span style="color:#000000">( 1000 );</span></p><p style="margin:0"><span style="color:#000000">            </span><span style="color:#7f0055;font-weight:bold">return</span><span style="color:#000000"> </span><span style="color:#6a3e3e">p</span><span style="color:#000000">;</span></p><p style="margin:0"><span style="color:#000000">        }</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#646464">@</span><span style="color:#646464">Override</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">protected</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">void</span><span style="color:#000000"> succeeded() {</span></p><p style="margin:0"><span style="color:#000000">            </span><span style="color:#0000c0">bp</span><span style="color:#000000">.setCenter( getValue() );</span></p><p style="margin:0"><span style="color:#000000">        }</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#646464">@</span><span style="color:#646464">Override</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">protected</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">void</span><span style="color:#000000"> failed() {</span></p><p style="margin:0"><span style="color:#000000">            getException().printStackTrace();</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></div>
              </div>
            </div>
            <div>
              <div style="background-color:#ffffff;padding:0px 2px 0px 2px">
                <div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><p style="margin:0">------------------------------------------------------------------------------------------------------</p></div>
              </div>
            </div>
            <div><br>
            </div>
            <div>
              <div style="background-color:#ffffff;padding:0px 2px 0px 2px">
                <div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><p style="margin:0"><span style="color:#7f0055;font-weight:bold">public</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">class</span><span style="color:#000000"> TestView</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">@</span><span style="color:#646464">FXML</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">private</span><span style="color:#000000"> Label </span><span style="color:#0000c0">memory</span><span style="color:#000000">;</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">    </span><span style="color:#7f0055;font-weight:bold">private</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">static</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">final</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">double</span><span style="color:#000000">  </span><span style="color:#0000c0;font-style:italic;font-weight:bold">MEGABYTE</span><span style="color:#000000"> = 1024 * 1024;</span></p><p style="margin:0">
</p><p style="margin:0"><span style="color:#000000">    </span><span style="color:#646464">@</span><span style="color:#646464">FXML</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">private</span><span style="color:#000000"> </span><span style="color:#7f0055;font-weight:bold">void</span><span style="color:#000000"> initialize()</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">var</span><span style="color:#000000"> </span><span style="color:#6a3e3e">updater</span><span style="color:#000000"> = </span><span style="color:#7f0055;font-weight:bold">new</span><span style="color:#000000"> Timeline</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">new</span><span style="color:#000000"> KeyFrame( Duration.</span><span style="color:#000000;font-style:italic">seconds</span><span style="color:#000000">(2.5), </span><span style="color:#6a3e3e">event</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:#7f0055;font-weight:bold">var</span><span style="color:#000000"> </span><span style="color:#6a3e3e">runtime</span><span style="color:#000000"> = Runtime.</span><span style="color:#000000;font-style:italic">getRuntime</span><span style="color:#000000">();</span></p><p style="margin:0"><span style="color:#000000">                </span><span style="color:#7f0055;font-weight:bold">double</span><span style="color:#000000"> </span><span style="color:#6a3e3e">maxMemory</span><span style="color:#000000"> = </span><span style="color:#6a3e3e">runtime</span><span style="color:#000000">.maxMemory() / </span><span style="color:#0000c0;font-style:italic;font-weight:bold">MEGABYTE</span><span style="color:#000000">;</span></p><p style="margin:0"><span style="color:#000000">                </span><span style="color:#7f0055;font-weight:bold">double</span><span style="color:#000000"> </span><span style="color:#6a3e3e">usedMemory</span><span style="color:#000000"> = (</span><span style="color:#6a3e3e">runtime</span><span style="color:#000000">.totalMemory() - </span><span style="color:#6a3e3e">runtime</span><span style="color:#000000">.freeMemory()) / </span><span style="color:#0000c0;font-style:italic;font-weight:bold">MEGABYTE</span><span style="color:#000000">;</span></p><p style="margin:0"><span style="color:#000000">                </span><span style="color:#0000c0">memory</span><span style="color:#000000">.setText( (</span><span style="color:#7f0055;font-weight:bold">int</span><span style="color:#000000">) </span><span style="color:#6a3e3e">usedMemory</span><span style="color:#000000"> + </span><span style="color:#2a00ff">" MB / "</span><span style="color:#000000"> + (</span><span style="color:#7f0055;font-weight:bold">int</span><span style="color:#000000">) </span><span style="color:#6a3e3e">maxMemory</span><span style="color:#000000"> +</span><span style="color:#2a00ff">" MB"</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">
</p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#6a3e3e">updater</span><span style="color:#000000">.setCycleCount(Animation.</span><span style="color:#0000c0;font-style:italic;font-weight:bold">INDEFINITE</span><span style="color:#000000">);
        // This FXML is being loaded on a background thread
</span></p><p style="margin:0"><span style="color:#000000">        </span><span style="color:#6a3e3e">updater</span><span style="color:#000000">.play();</span></p><p style="margin:0"><span style="color:#000000">    }</span></p><p style="margin:0"><span style="color:#000000">}

</span></p></div>
              </div>
            </div>
            <div>
              <div style="background-color:#ffffff;padding:0px 2px 0px 2px">
                <div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><p style="margin:0">------------------------------------------------------------------------------------------------------</p></div>
              </div>
            </div>
            <div><br>
            </div>
            <div>
              <span style="color:#000000"><big>TestView.fxml</big></span>
            </div>
            <div><br>
            </div>
            <div>
              <div style="background-color:#ffffff;padding:0px 2px 0px 2px">
                <div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><div style="background-color:#ffffff;padding:0px 2px 0px 2px"><div style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:10pt;white-space:pre-wrap"><p style="margin:0"><?xml version="1.0" encoding="UTF-8"?></p><p style="margin:0">
</p><p style="margin:0"><?import javafx.scene.control.Label?></p><p style="margin:0"><?import javafx.scene.layout.StackPane?></p><p style="margin:0">
</p><p style="margin:0"><StackPane xmlns:fx="<a href="http://javafx.com/fxml/1" target="_blank" rel="noreferrer" moz-do-not-send="true" class="moz-txt-link-freetext">http://javafx.com/fxml/1</a>" fx:controller="TestView"></p><p style="margin:0">   <children></p><p style="margin:0">      <Label fx:id="memory" text="Current / Max MB" ></p><p style="margin:0">         <properties hashCode="12345" /></p><p style="margin:0">      </Label></p><p style="margin:0">   </children></p><p style="margin:0"></StackPane></p></div></div></div>
              </div>
            </div>
            <div><br>
            </div>
            <div><br>
            </div>
            <div><br>
            </div>
            <div>On Sat, 20 Jan 2024 17:08:41 +0200, Nir Lisker <<a href="mailto:nlisker@gmail.com" target="_blank" rel="noreferrer" moz-do-not-send="true" class="moz-txt-link-freetext">nlisker@gmail.com</a>>
              wrote:<br>
            </div>
            <br>
            <blockquote style="margin:0 0 0.80ex;border-left:#0000ff 2px solid;padding-left:1ex">
              <div dir="ltr">Hi Jurgen,
                <div><br>
                </div>
                <div>What I'm confused about the most is what it is you
                  are actually trying to do that necessitates the use of
                  animations outside of the FX thread. You said that you
                  need to initialize controls on another thread, and
                  that you are using Task (both of which are fine), but
                  how does playing animations relate? Playing an
                  animation is something that is done explicitly,
                  usually in order to manipulate data. Can you give a
                  real use case, like a minimized version of what you're
                  doing?</div>
                <div><br>
                </div>
                <div>- Nir</div>
              </div>
            </blockquote>
          </div>
        </blockquote>
      </div>
    </blockquote>
    <br>
  </body>
</html>