On Mon, 29 Jun 2020 11:33:24 GMT, Johan Vos <j...@openjdk.org> wrote:

>> I think the code in the `_stop` method is correct after all.
>> 
>> The `MonocleTimer` class is written to allow for multiple calls to the pair 
>> of `_start` and `_stop` methods (even
>> though I don't think that ever happens), and the static 
>> `ScheduledThreadPoolExecutor`, named `scheduler`, is created
>> only once and reused on subsequent calls.  Changing the `_stop` method to 
>> call `task.cancel(true)` still leaves the
>> timer thread running, which prevents the JavaFX application from exiting 
>> when the timer thread is a user thread.
>> Furthermore, whether it's a user or daemon thread, if the call to 
>> `task.cancel(true)` happens to run exactly when the
>> periodic task is *in progress*, the `timerRunnable` lambda in 
>> `QuantumToolkit` prints the stack trace when it catches
>> the `InterruptedException`.  java.lang.InterruptedException:
>>   at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit
>>        .lambda$runToolkit$12(QuantumToolkit.java:345)
>>   at java.base/java.util.concurrent.Executors$RunnableAdapter
>>        .call(Executors.java:515)
>>   at java.base/java.util.concurrent.FutureTask
>>        .runAndReset(FutureTask.java:305)
>>   at 
>> java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask
>>        .run(ScheduledThreadPoolExecutor.java:305)
>>   at java.base/java.util.concurrent.ThreadPoolExecutor
>>        .runWorker(ThreadPoolExecutor.java:1130)
>>   at java.base/java.util.concurrent.ThreadPoolExecutor$Worker
>>        .run(ThreadPoolExecutor.java:630)
>>   at java.base/java.lang.Thread
>>        .run(Thread.java:832)
>> 
>> So the call to `task.cancel(false)` is correct.
>> 
>> Changing the `_stop` method to shut down the `scheduler` will terminate the 
>> associated thread, regardless of its daemon
>> status, but a subsequent call to `_start` will throw a 
>> `RejectedExecutionException` when trying to schedule the timer
>> task:  java.util.concurrent.RejectedExecutionException:
>>   Task 
>> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@b1fe89
>>   [Not completed, task = 
>> java.util.concurrent.Executors$RunnableAdapter@1f85c96
>>   [Wrapped task = 
>> com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$111/0x34563828@141859b]]
>>   rejected from java.util.concurrent.ScheduledThreadPoolExecutor@55f462
>>   [Terminated, pool size = 0, active threads = 0, queued tasks = 0, 
>> completed tasks = 0]
>>   at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy
>>        .rejectedExecution(ThreadPoolExecutor.java:2057)
>>   at java.base/java.util.concurrent.ThreadPoolExecutor
>>        .reject(ThreadPoolExecutor.java:827)
>>   at java.base/java.util.concurrent.ScheduledThreadPoolExecutor
>>        .delayedExecute(ScheduledThreadPoolExecutor.java:340)
>>   at java.base/java.util.concurrent.ScheduledThreadPoolExecutor
>>        .scheduleAtFixedRate(ScheduledThreadPoolExecutor.java:632)
>>   at javafx.graphics/com.sun.glass.ui.monocle.MonocleTimer
>>        ._start(MonocleTimer.java:64)
>>   at javafx.graphics/com.sun.glass.ui.Timer
>>        .start(Timer.java:96)
>>   at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit
>>        .runToolkit(QuantumToolkit.java:384)
>>   at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit
>>        .lambda$startup$10(QuantumToolkit.java:280)
>>   at javafx.graphics/com.sun.glass.ui.Application
>>        .lambda$run$1(Application.java:153)
>>   at javafx.graphics/com.sun.glass.ui.monocle.RunnableProcessor
>>        .runLoop(RunnableProcessor.java:92)
>>   at javafx.graphics/com.sun.glass.ui.monocle.RunnableProcessor
>>        .run(RunnableProcessor.java:51)
>>   at java.base/java.lang.Thread
>>        .run(Thread.java:832)
>> 
>> So if we want `MonocleTimer` to reuse a single `ScheduledThreadPoolExecutor` 
>> object, I think the only way to make sure
>> that its timer thread exits when the application exits is to set its daemon 
>> status to `true`.
>
> While the PR should indeed fix the original issue, I'm unsure about the 
> behavior of multiple invocations of start/stop
> rather than using the (nop) pause method. However, it seems this behavior is 
> similar on other platforms, so I assume it
> is by design.

Given that this is a regression introduced in JavaFX 14, this fix seems like a 
good candidate for JavaFX 15, so I
recommend to _not_ merge the master branch.

Go ahead and retarget your PR to the `jfx15` branch (you should not need to 
merge anything), although we will need to
satisfy ourselves that the risk of further regression is low.

-------------

PR: https://git.openjdk.java.net/jfx/pull/256

Reply via email to