[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-openjfx-dev
Subject:    Synchronized Observable List
From:       richard.bair () oracle ! com (Richard Bair)
Date:       2012-09-24 14:18:48
Message-ID: 9E4A01A0-C408-4683-91FE-444E0A01C0C3 () oracle ! com
[Download RAW message or body]

    private static class SynchronizedList<T> implements List<T> {
        final Object mutex;
        private final List<T> backingList;

        SynchronizedList(List<T> list, Object mutex) {
            this.backingList = list;
            this.mutex = mutex;
        }

        SynchronizedList(List<T> seq) {
            this (seq, new Object());
        }


        @Override
        public int size() {
            synchronized(mutex) {
                return backingList.size();
            }
        }

        @Override
        public boolean isEmpty() {
            synchronized(mutex) {
                return backingList.isEmpty();
            }
        }

        @Override
        public boolean contains(Object o) {
            synchronized(mutex) {
                return backingList.contains(o);
            }
        }

        @Override
        public Iterator<T> iterator() {
            return backingList.iterator();
        }

        @Override
        public Object[] toArray() {
            synchronized(mutex)  {
                return backingList.toArray();
            }
        }

        @Override
        public <T> T[] toArray(T[] a) {
            synchronized(mutex) {
                return backingList.toArray(a);
            }
        }

        @Override
        public boolean add(T e) {
            synchronized(mutex) {
                return backingList.add(e);
            }
        }

        @Override
        public boolean remove(Object o) {
            synchronized(mutex) {
                return backingList.remove(o);
            }
        }

        @Override
        public boolean containsAll(Collection<?> c) {
            synchronized(mutex) {
                return backingList.containsAll(c);
            }
        }

        @Override
        public boolean addAll(Collection<? extends T> c) {
            synchronized(mutex) {
                return backingList.addAll(c);
            }
        }

        @Override
        public boolean addAll(int index, Collection<? extends T> c) {
            synchronized(mutex) {
                return backingList.addAll(index, c);

            }
        }

        @Override
        public boolean removeAll(Collection<?> c) {
            synchronized(mutex) {
                return backingList.removeAll(c);
            }
        }

        @Override
        public boolean retainAll(Collection<?> c) {
            synchronized(mutex) {
                return backingList.retainAll(c);
            }
        }

        @Override
        public void clear() {
            synchronized(mutex) {
                backingList.clear();
            }
        }

        @Override
        public T get(int index) {
            synchronized(mutex) {
                return backingList.get(index);
            }
        }

        @Override
        public T set(int index, T element) {
            synchronized(mutex) {
                return backingList.set(index, element);
            }
        }

        @Override
        public void add(int index, T element) {
            synchronized(mutex) {
                backingList.add(index, element);
            }
        }

        @Override
        public T remove(int index) {
            synchronized(mutex) {
                return backingList.remove(index);
            }
        }

        @Override
        public int indexOf(Object o) {
            synchronized(mutex) {
                return backingList.indexOf(o);
            }
        }

        @Override
        public int lastIndexOf(Object o) {
            synchronized(mutex) {
                return backingList.lastIndexOf(o);
            }
        }

        @Override
        public ListIterator<T> listIterator() {
            return backingList.listIterator();
        }

        @Override
        public ListIterator<T> listIterator(int index) {
            synchronized(mutex) {
                return backingList.listIterator(index);
            }
        }

        @Override
        public List<T> subList(int fromIndex, int toIndex) {
            synchronized(mutex) {
                return new SynchronizedList<T>(backingList.subList(fromIndex, \
toIndex),  mutex);
            }
        }

    }

    private static class SynchronizedObservableList<T> extends SynchronizedList<T> \
implements ObservableList<T> {

        private final ObservableList<T> backingList;

        SynchronizedObservableList(ObservableList<T> seq, Object mutex) {
            super(seq, mutex);
            this.backingList = seq;
        }

        SynchronizedObservableList(ObservableList<T> seq) {
            this(seq, new Object());
        }

        @Override
        public boolean addAll(T... elements) {
            synchronized(mutex) {
                return backingList.addAll(elements);
            }
        }

        @Override
        public boolean setAll(T... elements) {
            synchronized(mutex) {
                return backingList.setAll(elements);
            }
        }

        @Override
        public boolean removeAll(T... elements) {
            synchronized(mutex) {
                return backingList.removeAll(elements);
            }
        }

        @Override
        public boolean retainAll(T... elements) {
            synchronized(mutex) {
                return backingList.retainAll(elements);
            }
        }

        @Override
        public void remove(int from, int to) {
            synchronized(mutex) {
                backingList.remove(from, to);
            }
        }

        @Override
        public boolean setAll(Collection<? extends T> col) {
            synchronized(mutex) {
                return backingList.setAll(col);
            }
        }

        @Override
        public final void addListener(InvalidationListener listener) {
            backingList.addListener(listener);
        }
        
        @Override
        public final void removeListener(InvalidationListener listener) {
            backingList.removeListener(listener);
        }
        
        @Override
        public void addListener(ListChangeListener<? super T> o) {
            backingList.addListener(o);
        }

        @Override
        public void removeListener(ListChangeListener<? super T> o) {
            backingList.removeListener(o);
        }


    }

On Sep 22, 2012, at 2:58 PM, Bruce Alspaugh wrote:

> I'm new to JavaFX, so I was browsing the Javadoc for:
> 
> FXCollections#synchronizedObservableList(ObservableList<?>)
> 
> It doesn't say whether it synchronizes on the returned list or some
> other object that might not be accessible to me.  Can I safely assume it
> synchronizes on the intrinsic lock of the wrapper?
> 
> A potential problem with observable synchronized collections is that you
> have to be very careful not to call an "alien" method while holding a
> lock which risks deadlock and other synchronization problems as
> described in Item 67 of Effective Java.  In this case, the listeners
> registered on the wrapper would be considered "alien" to JavaFX.  If the
> wrapper naively holds the lock while forwarding the call to the
> corresponding method of the wrapped list, the lock would be held during
> the time the listeners are being notified, risking exceptions and
> deadlock.
> 
> One approach to work around this issue would be to use a condition
> variable on the lock to temporarily suspend it while the registered
> listeners are notified, and then regain it after the listeners have been
> notified.  This would require some sophistication and overhead to the
> underlying code that notifies listeners in JavaFX.
> 
> I have concerns about the approach of moving the listener notifications
> outside the critical section and the CopyOnWriteArrayList approach as
> described in Effective Java Item 67, because you can't guarantee the
> order that listeners are notified when multiple threads concurrently
> modify the collection, and the listeners themselves would have to be
> able to handle concurrent notification.  For example, if thread 1 makes
> change A and thread 2 makes change B to the same collection, you can't
> guarantee that a listener would be notified of A before B, B before A,
> or it could be concurrently notified of A and B.  I also don't see how
> Dr. Bloch is guarding the backing Set from concurrent modification.  I
> understand it could be a thread-safe Set, like CopyOnWriteArraySet, but
> there is nothing to guarantee it is so.
> 
> I suppose the simplest approach of all would be to simply confine
> observable collections to a single thread.  What is the use case that
> requires an observable collection to be concurrently modified?  Could
> the use case be handled some other way?
> 
> If someone could point me to where I can browse the JavaFX source code
> so I can see what is actually going on here, it would be quite helpful. 
> 
> Thanks,
> 
> Bruce
> 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic