<Swing Dev> [9] Review Request for 8130735: javax.swing.TimerQueue: timer fires late when another timer starts

Alexander Scherbatiy alexandr.scherbatiy at oracle.com
Tue Jul 21 11:31:55 UTC 2015


On 7/21/2015 1:40 PM, Semyon Sadetsky wrote:
> In the run() the delayed timer is obtained from timer, so it is always 
> the resulting delayed timer.
    Just to use the delayed timer from the queue and not from the timer?

TimerQueue.run(){
     DelayedTimer delayedTimer = queue.take(); // note that this delayed 
timer is not the same as timer.delayedTimer
     delayedTimer.getTimer().lock();
     if(delayedTimer.removed){
         // skip it
     }
     // ...
     delayedTimer.getTimer().unlock();
}

Thanks,
Alexandr.


> How do you propose to detect that timer was renewed exactly during the 
> time interval between the timer is taken from the queue and the lock 
> is captured in the run() thread?
>
> On 7/21/2015 12:53 PM, Alexander Scherbatiy wrote:
>> On 7/21/2015 11:36 AM, Semyon Sadetsky wrote:
>>> Hi Alexander,
>>>
>>> The remove() method set delayedTimer field to null, and it is 
>>> checked in run() to be not null. So it acts in the same way as flag 
>>> you've proposed.
>>>
>>> The issue is about how to detect consequent remove() ans add() in 
>>> run(). If you use some flag in remove() then you need to clear it in 
>>> add()
>>     I suppose that you are talking about some flags in Timer. The 
>> proposed change suggests to add the flag to the DelayedTimer. So 
>> after stopping a timer (timer.delayedTimer = null) the delayedTimer 
>> taken from the queue contains information that it has been removed.
>>
>>   Thanks,
>>   Alexandr.
>>
>>> because after the add() the timer should run normally with the new 
>>> period.  And you cannot clear such flag in the first consequent 
>>> run() after add() because you cannot determine the moment the add() 
>>> was called. So it is just the same problem.
>>>
>>> --Semyon
>>>
>>> On 7/21/2015 10:35 AM, Alexander Scherbatiy wrote:
>>>>
>>>>   What about to add removed flat to DelayedTimer? Something like:
>>>>   TimerQueue.removeTimer(Timer timer){
>>>>     timer.lock();
>>>>     // ...
>>>>     timer.delayedTimer.removed = true;
>>>>     queue.remove(timer.delayedTimer);
>>>>     timer.delayedTimer = null;
>>>>     timer.unlock();
>>>> }
>>>>
>>>> TimerQueue.run(){
>>>>     DelayedTimer delayedTimer = queue.take();
>>>>     delayedTimer.getTimer().lock();
>>>>     if(delayedTimer.removed){
>>>>         // skip it
>>>>     }
>>>>     // ...
>>>>     delayedTimer.getTimer().unlock();
>>>> }
>>>>
>>>>  Thanks,
>>>>  Alexandr.
>>>>
>>>>
>>>> On 7/17/2015 12:28 AM, Sergey Bylokhov wrote:
>>>>> Hi, Semyon.
>>>>> I see that the chance to reproduce the problem is very very small, 
>>>>> because we should call addTimer, when we are at lines 171/172. So 
>>>>> the bug is about really small timings. So the related question: Is 
>>>>> it possible in the fixed version to call addTimer when we remove 
>>>>> DelayedTimer from the queue via queue.take(), but before we assign 
>>>>> its value to the runningTimer?
>>>>>
>>>>> On 14.07.15 12:51, Alexander Zvegintsev wrote:
>>>>>> still looks good to me.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Alexander.
>>>>>>
>>>>>> On 07/14/2015 12:41 PM, Semyon Sadetsky wrote:
>>>>>>> Hi Alexander,
>>>>>>>
>>>>>>> I added the double check 
>>>>>>> :http://cr.openjdk.java.net/~ssadetsky/8130735/webrev.01/
>>>>>>>
>>>>>>> --Semyon
>>>>>>>
>>>>>>> On 7/13/2015 1:24 PM, Alexander Zvegintsev wrote:
>>>>>>>> Hello Semyon,
>>>>>>>>
>>>>>>>> the fix looks good to me.
>>>>>>>>
>>>>>>>> P.S. Just a side note, as I can see we could possibly start two 
>>>>>>>> threads instead of one in startIfNeeded():
>>>>>>>>
>>>>>>>>   96     void startIfNeeded() {
>>>>>>>>   97         if (! running) {
>>>>>>>>   98             runningLock.lock();
>>>>>>>>   99             try {
>>>>>>>>  100                 final ThreadGroup threadGroup = 
>>>>>>>> AppContext.getAppContext().getThreadGroup();
>>>>>>>>  101 AccessController.doPrivileged((PrivilegedAction<Object>) 
>>>>>>>> () -> {
>>>>>>>>  102                     String name = "TimerQueue";
>>>>>>>>  103                     Thread timerThread = new 
>>>>>>>> ManagedLocalsThread(threadGroup,
>>>>>>>>  104 this, name);
>>>>>>>>
>>>>>>>> !running check is missing after try. It is not the case with 
>>>>>>>> current code base, but it may be changed in future.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>>
>>>>>>>> Alexander.
>>>>>>>>
>>>>>>>> On 07/09/2015 08:08 PM, Semyon Sadetsky wrote:
>>>>>>>>> Hello,
>>>>>>>>>
>>>>>>>>> Please review fix for JDK9:
>>>>>>>>>
>>>>>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8130735
>>>>>>>>> webrev: http://cr.openjdk.java.net/~ssadetsky/8130735/webrev.00/
>>>>>>>>>
>>>>>>>>> The root cause is the setting larger expiration time for the 
>>>>>>>>> timer which is already inserted into the delay queue. So all 
>>>>>>>>> timers behind the timer cannot be executed earlier than its 
>>>>>>>>> expiration time. This happens very rare only for repeated 
>>>>>>>>> timers and only if user uses the Swing timer API inaccurately 
>>>>>>>>> (call start() without stop()).
>>>>>>>>> The fix eliminates this possibility by introducing a check if 
>>>>>>>>> the timer was already restarted concurrently.
>>>>>>>>> It is difficult to write test because I could not reliably 
>>>>>>>>> reproduce the issue for a reasonable time.
>>>>>>>>>
>>>>>>>>> --Semyon
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>> -- 
>>>>> Best regards, Sergey.
>>>>
>>>
>>
>




More information about the swing-dev mailing list