On 10/15/2012 01:45 PM, David Holmes wrote: > On 15/10/2012 8:08 PM, Jaroslav Bachorik wrote: >> On 10/15/2012 04:19 AM, David Holmes wrote: >>> I think your changes now go further than needed. The original code uses >>> a dual synchronization scheme: >>> >>> a) it synchronizes most of the Timer methods >>> b) it also uses a thread-safe Hashtable >>> >>> This means that not all of the Timer methods need to be synchronized >>> because the only thread-safe action needed is the actual access to the >>> Hashtable in some methods. >>> >>> The flaw with the original code was simply that the iteration of the >>> Hashtable in notifyAlaramClock was not done in a thread-safe manner. I >>> believe this could be fixed simply by synchronizing on the Hashtable >>> here: >>> >>> 1186 synchronized(timerTable) { >>> >>> with no need to change the type of the timerTable, nor the >>> synchronization on other Timer methods. You could alternatively >>> synchronize on the Timer itself - as you now do - provided all methods >>> of the Timer that mutate the Hashtable are themselves synchronized on >>> the timer. >>> >>> What you have is not incorrect though, and may remove unnecessary >>> synchronization in some cases (but increases the size of critical >>> sections in others). >>> >>> Also here: >>> >>> 165 volatile private int counterID = 0; >>> >>> there is no need to add volatile as counterID is only accessed within >>> synchronized methods. >> >> Yes, I see your point. I just want to ask - in cases of fixing issues >> like this the preferred way is to introduce minimal changes even if it >> means leaving the parts of the code sub-optimal? IMO, having dual >> synchronization scheme might be considered as sub-optimal as it makes it >> more difficult to see the author's intentions. > > Optimal depends on your evaluation criteria. The original design may > have been done with performance in mind and a view to minimising > critical sections. Without knowing what the original design criteria > was, and unless you are fixing a problem caused by key aspects of that > design, then minimal changes should be favoured. > >> But I am fine with leaving the Hashtable intact and just synchronizing >> the iteration part correctly - it resolves the issue. >> >> The update webrev is available at >> http://btrace.kenai.com/webrevs/JDK-6809322/webrev.v4 > > I'm not sure the comment is needed in that form. Hashtable is > snchronized internally but you need to use external synchronization when > iterating through it.
Ok, it's gone. http://btrace.kenai.com/webrevs/JDK-6809322/webrev.v5/ > > David > >> Regards, >> >> -JB- >> >>> >>> David >>> ----- >>> >>> On 12/10/2012 11:14 PM, Jaroslav Bachorik wrote: >>>> The updated webrev is now at >>>> http://btrace.kenai.com/webrevs/JDK-6809322/ >>>> >>>> I am sorry for this chaos with webrev locations but its not that >>>> easy to >>>> work efficiently without an OpenJDK username :/ >>>> >>>> -JB- >>>> >>>> On 10/12/2012 09:47 AM, Jaroslav Bachorik wrote: >>>>> On Fri 12 Oct 2012 04:44:31 AM CEST, David Holmes wrote: >>>>>> Hi Jaroslav, >>>>>> >>>>>> >>>>>> On 11/10/2012 6:07 PM, Jaroslav Bachorik wrote: >>>>>>> Dmitry has put the webrev on the public CR - >>>>>>> http://cr.openjdk.java.net/~dsamersoff/sponsorship/jbachorik/JDK-6809322-v2/ >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> Thanks! >>>>>>> >>>>>>> -JB- >>>>>>> >>>>>>> On 10/10/2012 04:17 PM, Jaroslav Bachorik wrote: >>>>>>>> I am looking for a review and a sponsor. >>>>>>>> >>>>>>>> The issue is about some javax.management.timer.Timer notifications >>>>>>>> not >>>>>>>> being received by the listeners if the notifications are generated >>>>>>>> rapidly. >>>>>>>> >>>>>>>> The problem is caused by ConcurrentModificationException being >>>>>>>> thrown - >>>>>>>> the exception itself is ignored but the dispatcher logic is >>>>>>>> skipped. >>>>>>>> Therefore the currently processed notification gets lost. >>>>>> >>>>>> Can you point out where exactly in the code the exception is thrown >>>>>> and caught. I'd like to understand the problem better. >>>>> >>>>> The CME is thrown in Timer.notifyAlarmClock() method in this case - >>>>> but >>>>> may happen in other places as well. >>>>> >>>>> Actually, in some places the access to the timerTable map is >>>>> synchronized while in others it isn't. While switching the Hashtable >>>>> for ConcurrentHashMap resolves this particular issue it might be >>>>> beneficial to correct the partial synchronization instead. >>>>> >>>>>> >>>>>>>> >>>>>>>> The CME is thrown due to the Timer.timerTable being iterated over >>>>>>>> while >>>>>>>> other threads try to remove some of its elements. Fix consists of >>>>>>>> replacing the Hashtable used for Timer.timerTable by >>>>>>>> ConcurrentHashMap >>>>>>>> which handles such situations with grace. >>>>>> >>>>>> Be aware that it may also give surprising results as removal is no >>>>>> longer synchronized at all with processing. So it could now appear >>>>>> that a notification is processed after a listener has been removed. >>>>> >>>>> Indeed, the CME is the symptom of the out-of-order processing - the >>>>> removal method is synchronized on (Timer.this) while the >>>>> notifyAlarmClock() method, processing the notifications, runs >>>>> unsynchronized. >>>>> >>>>> Thanks for pointing this out. I will have something to think about. >>>>> >>>>> -JB- >>>>> >>>>>> >>>>>> David >>>>>> ----- >>>>>> >>>>>>>> The patch webrev is available @ >>>>>>>> https://jbs.oracle.com/bugs/browse/JDK-6809322 >>>>>>>> >>>>>>>> Thanks, >>>>>>>> >>>>>>>> -JB- >>>>>>>> >>>>>>> >>>>> >>>>> >>>> >>