Speed up listener notification

Discover the fastest way to notify event listeners defined by the JavaBeans 1.01 specification

1 2 3 Page 3
Page 3 of 3

< center> <table border="0" cellpadding="0" cellspacing="0"> <tr> <td> <div id="analyze_11371" align="center" x:publishsource="Excel"> <br/> <br/> <table x:str="x:str" border="0" cellpadding="0" cellspacing="0" width="444" style="border-collapse: collapse;table-layout:fixed;width:333pt"> <col width="20" span="3" style="mso-width-source:userset;mso-width-alt:731; width:15pt"/> <col width="64" span="6" style="width:48pt"/> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" colspan="4" width="124" style="height:12.75pt; width:93pt">Pentium II 300 MHz</td> <td class="xl1511371" width="64" style="width:48pt"></td> <td class="xl1511371" width="64" style="width:48pt"></td> <td class="xl1511371" width="64" style="width:48pt"></td> <td class="xl1511371" width="64" style="width:48pt"></td> <td class="xl2511371" width="64" style="width:48pt">Average</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371" colspan="7">Five runs of Source1 through Source7, plus an average of all runs, measured in seconds</td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" colspan="3">Sun JDK 1.1.8</td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">1</td> <td class="xl2411371" align="right" x:num="2.7040000000000002">2.704</td> <td class="xl2411371" align="right" x:num="2.7040000000000002">2.704</td> <td class="xl2411371" align="right" x:num="2.7040000000000002">2.704</td> <td class="xl2411371" align="right" x:num="2.694">2.694</td> <td class="xl2411371" align="right" x:num="2.694">2.694</td> <td class="xl2611371" align="right" x:num="x:num" x:fmla="=AVERAGE(D4:H4)">2.700</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">2</td> <td class="xl2411371" align="right" x:num="0.751">0.751</td> <td class="xl2411371" align="right" x:num="0.74099999999999999">0.741</td> <td class="xl2411371" align="right" x:num="0.752">0.752</td> <td class="xl2411371" align="right" x:num="0.76100000000000001">0.761</td> <td class="xl2411371" align="right" x:num="0.76200000000000001">0.762</td> <td class="xl2611371" align="right" x:num="0.75339999999999996" x:fmla="=AVERAGE(D5:H5)">0.753</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">3</td> <td class="xl2411371" align="right" x:num="00.57">0.570</td> <td class="xl2411371" align="right" x:num="0.57099999999999995">0.571</td> <td class="xl2411371" align="right" x:num="00.55">0.550</td> <td class="xl2411371" align="right" x:num="0.57099999999999995">0.571</td> <td class="xl2411371" align="right" x:num="00.57">0.570</td> <td class="xl2611371" align="right" x:num="0.56640000000000001" x:fmla="=AVERAGE(D6:H6)">0.566</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">4</td> <td class="xl2411371" align="right" x:num="0.45100000000000001">0.451</td> <td class="xl2411371" align="right" x:num="0.45100000000000001">0.451</td> <td class="xl2411371" align="right" x:num="0.46100000000000002">0.461</td> <td class="xl2411371" align="right" x:num="0.45100000000000001">0.451</td> <td class="xl2411371" align="right" x:num="0.45100000000000001">0.451</td> <td class="xl2611371" align="right" x:num="0.45300000000000001" x:fmla="=AVERAGE(D7:H7)">0.453</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">5</td> <td class="xl2411371" align="right" x:num="2.9540000000000002">2.954</td> <td class="xl2411371" align="right" x:num="2.9540000000000002">2.954</td> <td class="xl2411371" align="right" x:num="2.964">2.964</td> <td class="xl2411371" align="right" x:num="2.9540000000000002">2.954</td> <td class="xl2411371" align="right" x:num="2.9540000000000002">2.954</td> <td class="xl2611371" align="right" x:num="2.9560000000000004" x:fmla="=AVERAGE(D8:H8)">2.956</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">6</td> <td class="xl2411371" align="right" x:num="0.65100000000000002">0.651</td> <td class="xl2411371" align="right" x:num="0.66100000000000003">0.661</td> <td class="xl2411371" align="right" x:num="0.63100000000000001">0.631</td> <td class="xl2411371" align="right" x:num="0.65100000000000002">0.651</td> <td class="xl2411371" align="right" x:num="0.65100000000000002">0.651</td> <td class="xl2611371" align="right" x:num="0.64900000000000002" x:fmla="=AVERAGE(D9:H9)">0.649</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">7</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2611371" align="right" x:num="00.12" x:fmla="=AVERAGE(D10:H10)">0.120</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" colspan="3">IBM JDK 1.1.8</td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">1</td> <td class="xl2411371" align="right" x:num="0.95199999999999996">0.952</td> <td class="xl2411371" align="right" x:num="0.94099999999999995">0.941</td> <td class="xl2411371" align="right" x:num="0.94099999999999995">0.941</td> <td class="xl2411371" align="right" x:num="0.94099999999999995">0.941</td> <td class="xl2411371" align="right" x:num="0.93200000000000005">0.932</td> <td class="xl2611371" align="right" x:num="0.94140000000000001" x:fmla="=AVERAGE(D13:H13)">0.941</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">2</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2411371" align="right" x:num="0.191">0.191</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2411371" align="right" x:num="0.191">0.191</td> <td class="xl2411371" align="right" x:num="00.17">0.170</td> <td class="xl2611371" align="right" x:num="0.18240000000000001" x:fmla="=AVERAGE(D14:H14)">0.182</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">3</td> <td class="xl2411371" align="right" x:num="0.26100000000000001">0.261</td> <td class="xl2411371" align="right" x:num="x:num">0.250</td> <td class="xl2411371" align="right" x:num="0.251">0.251</td> <td class="xl2411371" align="right" x:num="x:num">0.250</td> <td class="xl2411371" align="right" x:num="0.24099999999999999">0.241</td> <td class="xl2611371" align="right" x:num="0.25060000000000004" x:fmla="=AVERAGE(D15:H15)">0.251</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">4</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2411371" align="right" x:num="0.18099999999999999">0.181</td> <td class="xl2411371" align="right" x:num="00.18">0.180</td> <td class="xl2611371" align="right" x:num="0.1802" x:fmla="=AVERAGE(D16:H16)">0.180</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">5</td> <td class="xl2411371" align="right" x:num="0.94099999999999995">0.941</td> <td class="xl2411371" align="right" x:num="0.94099999999999995">0.941</td> <td class="xl2411371" align="right" x:num="0.93100000000000005">0.931</td> <td class="xl2411371" align="right" x:num="0.95099999999999996">0.951</td> <td class="xl2411371" align="right" x:num="0.93100000000000005">0.931</td> <td class="xl2611371" align="right" x:num="0.93900000000000006" x:fmla="=AVERAGE(D17:H17)">0.939</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">6</td> <td class="xl2411371" align="right" x:num="0.26100000000000001">0.261</td> <td class="xl2411371" align="right" x:num="00.26">0.260</td> <td class="xl2411371" align="right" x:num="0.27100000000000002">0.271</td> <td class="xl2411371" align="right" x:num="x:num">0.250</td> <td class="xl2411371" align="right" x:num="0.26100000000000001">0.261</td> <td class="xl2611371" align="right" x:num="0.2606" x:fmla="=AVERAGE(D18:H18)">0.261</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">7</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2411371" align="right" x:num="00.13">0.130</td> <td class="xl2411371" align="right" x:num="00.13">0.130</td> <td class="xl2411371" align="right" x:num="00.13">0.130</td> <td class="xl2411371" align="right" x:num="00.12">0.120</td> <td class="xl2611371" align="right" x:num="0.126" x:fmla="=AVERAGE(D19:H19)">0.126</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" colspan="3">Sun JDK 1.3 Beta</td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> <td class="xl1511371"></td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">1</td> <td class="xl2411371" align="right" x:num="1.131">1.131</td> <td class="xl2411371" align="right" x:num="1.1120000000000001">1.112</td> <td class="xl2411371" align="right" x:num="1.121">1.121</td> <td class="xl2411371" align="right" x:num="1.1220000000000001">1.122</td> <td class="xl2411371" align="right" x:num="1.131">1.131</td> <td class="xl2611371" align="right" x:num="1.1234000000000002" x:fmla="=AVERAGE(D22:H22)">1.123</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">2</td> <td class="xl2411371" align="right" x:num="0.221">0.221</td> <td class="xl2411371" align="right" x:num="00.22">0.220</td> <td class="xl2411371" align="right" x:num="0.23100000000000001">0.231</td> <td class="xl2411371" align="right" x:num="00.22">0.220</td> <td class="xl2411371" align="right" x:num="0.221">0.221</td> <td class="xl2611371" align="right" x:num="0.22259999999999999" x:fmla="=AVERAGE(D23:H23)">0.223</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">3</td> <td class="xl2411371" align="right" x:num="00.31">0.310</td> <td class="xl2411371" align="right" x:num="0.32100000000000001">0.321</td> <td class="xl2411371" align="right" x:num="00.3">0.300</td> <td class="xl2411371" align="right" x:num="0.311">0.311</td> <td class="xl2411371" align="right" x:num="00.31">0.310</td> <td class="xl2611371" align="right" x:num="0.31040000000000001" x:fmla="=AVERAGE(D24:H24)">0.310</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">4</td> <td class="xl2411371" align="right" x:num="00.16">0.160</td> <td class="xl2411371" align="right" x:num="00.16">0.160</td> <td class="xl2411371" align="right" x:num="00.15">0.150</td> <td class="xl2411371" align="right" x:num="00.15">0.150</td> <td class="xl2411371" align="right" x:num="00.15">0.150</td> <td class="xl2611371" align="right" x:num="0.154" x:fmla="=AVERAGE(D25:H25)">0.154</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">5</td> <td class="xl2411371" align="right" x:num="1.032">1.032</td> <td class="xl2411371" align="right" x:num="1.0309999999999999">1.031</td> <td class="xl2411371" align="right" x:num="1.032">1.032</td> <td class="xl2411371" align="right" x:num="1.0409999999999999">1.041</td> <td class="xl2411371" align="right" x:num="1.032">1.032</td> <td class="xl2611371" align="right" x:num="1.0335999999999999" x:fmla="=AVERAGE(D26:H26)">1.034</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">6</td> <td class="xl2411371" align="right" x:num="00.28">0.280</td> <td class="xl2411371" align="right" x:num="0.28100000000000003">0.281</td> <td class="xl2411371" align="right" x:num="00.28">0.280</td> <td class="xl2411371" align="right" x:num="0.27100000000000002">0.271</td> <td class="xl2411371" align="right" x:num="00.28">0.280</td> <td class="xl2611371" align="right" x:num="0.27840000000000004" x:fmla="=AVERAGE(D27:H27)">0.278</td> </tr> <tr height="17" style="height:12.75pt"> <td height="17" class="xl1511371" style="height:12.75pt"></td> <td class="xl1511371"></td> <td class="xl1511371" align="right" x:num="x:num">7</td> <td class="xl2411371" align="right" x:num="00.1">0.100</td> <td class="xl2411371" align="right" x:num="00.09">0.090</td> <td class="xl2411371" align="right" x:num="00.1">0.100</td> <td class="xl2411371" align="right" x:num="00.09">0.090</td> <td class="xl2411371" align="right" x:num="00.09">0.090</td> <td class="xl2611371" align="right" x:num="9.4E-2" x:fmla="=AVERAGE(D28:H28)">0.094</td> </tr> <tr height="0" style="display:none"> <td width="20" style="width:15pt"></td> <td width="20" style="width:15pt"></td> <td width="20" style="width:15pt"></td> <td width="64" style="width:48pt"></td> <td width="64" style="width:48pt"></td> <td width="64" style="width:48pt"></td> <td width="64" style="width:48pt"></td> <td width="64" style="width:48pt"></td> <td width="64" style="width:48pt"></td> </tr> </table> <br/> <br/> </div> </td> </tr> </table> </center>

Performance numbers for Source1 through Source7, using three different JDKs

Conclusion

Let me start by noting that all of the optimizations in this article should be considered only after listener notification has been determined to be either a performance bottleneck or a source of many short-lived objects that in turn lead to a performance bottleneck. Consider a simple JavaBean that only generates events in response to user mouse clicks. In this case, the user will have a difficult time generating 500 events, let alone the benchmarked 50,000 events. Even at 500 events, the longest running average time would only be 0.0296 seconds.

However, once you have determined that your bottleneck is caused by this common programming technique -- that is, you have determined that your program creates a clone of a list of event listeners and then uses that list during the notification process -- it can be improved upon by moving the clone to the add<ListenerType>and remove<ListenerType>calls. It appears as though the DataItemChangeManagerSupport class uses clones in all of its implementations of event delivery methods, and is therefore a likely candidate for fast listener notification optimization. Using Swing's EventListenerList as documented gives you this optimization for free; at the same time, doing so continues to satisfy the rule that dictates that your code should ignore changes to the listener list during notification. You can even optimize your code further. Note that the EventListenerListuses a polymorphic list of listeners. It therefore has to search for the listeners to notify by matching the event type being notified with the event type registered. Furthermore, it must cast listeners to the correct listener interface. Thus, a custom array implementation can perform slightly better than the EventListenerList, but at the cost of increased memory usage. In the custom array implementation, each listener list to be notified requires an array object to store the list; on the other hand, the EventListenerList can multiplex events using a single array.

The only other short-lived object generated during listener notification is the event itself. EventListenerList's documented technique for caching the event further increases performance, but it is difficult to apply in practice. Events generally do not supply mutators, so events that, once cached, need to be changed require a derived class to supply mutators. InfoBus makes this impossible, because its events are declared with the final attribute. Furthermore, simple caching fails when used in a multithreaded environment, as documented in the EventListenerList. Swing is not a multithreaded environment, but InfoBus is. Object pooling, as discussed in "Java Performance Programming, Part 1: Smart Object Management Saves the Day" (see Resources) could be used to implement the cache, but the overhead and complexity might be prohibitive.

Furthermore, it appears that vendors of JIT compilers are making major progress in the effort to reduce the cost of object creation. For example, DefaultDataItemChangeManager is only twice as fast as DataItemChangeManagerSupport for the IBM compiler. Therefore, I think that optimizations focusing simply on reducing object creation and garbage collection will produce less dramatic improvements with future JITs. However, the elimination of clones will continue to result in at least a doubling of speed, with even better performance being possible if there are many listeners in the array being cloned.

Robert Hastingsis a senior software architect for Science and Engineering Associates, with over 10 years of experience developing software. He holds a MSCS from the University of California at Riverside. For the past six years, he has been involved in the design and development of advanced command and control systems for the Department of Defense, using C, C++, and, during the past year, such Java technologies as JavaBeans, Infobus, JAF, and Swing.

Learn more about this topic

Related:
1 2 3 Page 3
Page 3 of 3