This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 268047 - Performance issue - ancient synchronized implementations of listener subscriptions
Summary: Performance issue - ancient synchronized implementations of listener subscrip...
Status: NEW
Alias: None
Product: ide
Classification: Unclassified
Component: Performance (show other bugs)
Version: Dev
Hardware: PC Windows 7
: P3 normal (vote)
Assignee: Tomas Hurka
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-09-15 17:07 UTC by NukemBy
Modified: 2016-09-15 17:07 UTC (History)
0 users

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description NukemBy 2016-09-15 17:07:00 UTC
It does not cause a severe problems, but is noticeable as a hot spot in self profiler - synchronized add|remove|fireListeners() with internal cloning of the lists before firing of the events.

This can be re-implemented more easily and more performance-friendly using classes from Java 7 concurrent collections, for example:
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedDeque.html 
"Note: Iterators are weakly consistent, returning elements reflecting the state of the deque at some point at or since the creation of the iterator. They do not throw ConcurrentModificationException, and may proceed concurrently with other operations."
More details @ https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html


Examples:

api.debugger\src\org\netbeans\api\debugger\Lookup.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

        private final class MetaInfLookupList<T> extends LookupList<T> implements PositionedList<T>, Customizer {
            private List<PropertyChangeListener> propertyChangeListeners;

            @Override
            public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
                if (propertyChangeListeners == null) {
                    propertyChangeListeners = new ArrayList<PropertyChangeListener>();
                }
                propertyChangeListeners.add(listener);
            }

            @Override
            public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
                propertyChangeListeners.remove(listener);
            }
            
            private void firePropertyChange() {
                List<PropertyChangeListener> listeners;
                synchronized (this) {
                    if (propertyChangeListeners == null) {
                        return ;
                    }
                    listeners = new ArrayList<PropertyChangeListener>(propertyChangeListeners);
                }
                PropertyChangeEvent evt = new PropertyChangeEvent(this, "content", null, null);
                for (PropertyChangeListener l : listeners) {
                    l.propertyChange(evt);
                }
            }


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        private final class MetaInfLookupList<T> extends LookupList<T> implements PositionedList<T>, Customizer {
            private ConcurrentLinkedDeque<PropertyChangeListener> propertyChangeListeners = new ConcurrentLinkedDeque<>();

            @Override
            public void addPropertyChangeListener(PropertyChangeListener listener) {
                propertyChangeListeners.add(listener);
            }

            @Override
            public void removePropertyChangeListener(PropertyChangeListener listener) {
                propertyChangeListeners.remove(listener);
            }
            
            private void firePropertyChange() {
                if (propertyChangeListeners.isEmpty()) {
                    return ;
                }

                PropertyChangeEvent evt = new PropertyChangeEvent(this, "content", null, null);
                for (PropertyChangeListener l : propertyChangeListeners) {
                    l.propertyChange(evt);
                }
            }



Another similar use-case

api.debugger\src\org\netbeans\api\debugger\DebuggerManager.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

public final class DebuggerManager implements ContextProvider {

    private Vector                            listeners = new Vector ();
    private final HashMap                     listenersMap = new HashMap ();

    private void firePropertyChange (String name, Object o, Object n) {
        initDebuggerManagerListeners ();
        Vector l = (Vector) listeners.clone ();
        Vector l1;
        synchronized (listenersMap) {
            l1 = (Vector) listenersMap.get (name);
            if (l1 != null)
                l1 = (Vector) l1.clone ();
        }

        int i, k = l.size ();
        for (i = 0; i < k; i++) {
            try {
                ((DebuggerManagerListener)l.elementAt (i)).propertyChange (ev);
            } catch (Exception ex) {
                Exceptions.printStackTrace(ex);
            }
        }