ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java (file contents):
Revision 1.41 by dl, Tue May 31 17:39:18 2005 UTC vs.
Revision 1.42 by dl, Sun Jun 5 13:53:25 2005 UTC

# Line 16 | Line 16
16  
17   package java.util.concurrent;
18   import java.util.*;
19 + import java.util.concurrent.locks.*;
20 + import sun.misc.*;
21  
22   /**
23   * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
# Line 51 | Line 53 | public class CopyOnWriteArrayList<E>
53      implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
54      private static final long serialVersionUID = 8673264195747942595L;
55  
56 +    /** The lock protecting all mutators */
57 +    transient final ReentrantLock lock = new ReentrantLock();
58 +
59      /** The array, accessed only via getArray/setArray. */
60      private volatile transient Object[] array;
61  
62 <    private Object[]  getArray()           { return array; }
63 <    private void      setArray(Object[] a) { array = a; }
62 >    Object[]  getArray()           { return array; }
63 >    void      setArray(Object[] a) { array = a; }
64  
65      /**
66       * Creates an empty list.
# Line 103 | Line 108 | public class CopyOnWriteArrayList<E>
108       * @param n the number of elements to copy. This will be the new size of
109       * the list.
110       */
111 <    private synchronized void copyIn(E[] toCopyIn, int first, int n) {
111 >    private void copyIn(E[] toCopyIn, int first, int n) {
112          int limit = first + n;
113          if (limit > toCopyIn.length)
114              throw new IndexOutOfBoundsException();
115 <        setArray( cloneRange(toCopyIn, first, limit, Object[].class));
115 >        Object[] newElements = copyOfRange(toCopyIn, first, limit,
116 >                                          Object[].class);
117 >        final ReentrantLock lock = this.lock;
118 >        lock.lock();
119 >        try { setArray(newElements); }
120 >        finally { lock.unlock(); }
121      }
122  
123      /**
# Line 273 | Line 283 | public class CopyOnWriteArrayList<E>
283       */
284      public Object[] toArray() {
285          Object[] elements = getArray();
286 <        return clone(elements, elements.length);
286 >        return copyOf(elements, elements.length);
287      }
288  
289      /**
# Line 319 | Line 329 | public class CopyOnWriteArrayList<E>
329          Object[] elements = getArray();
330          int len = elements.length;
331          if (a.length < len)
332 <            return (T[]) clone(elements, len, a.getClass());
332 >            return (T[]) copyOf(elements, len, a.getClass());
333          else {
334              System.arraycopy(elements, 0, a, 0, len);
335              if (a.length > len)
# Line 345 | Line 355 | public class CopyOnWriteArrayList<E>
355       *
356       * @throws IndexOutOfBoundsException {@inheritDoc}
357       */
358 <    public synchronized E set(int index, E element) {
359 <        Object[] elements = getArray();
360 <        int len = elements.length;
361 <        Object oldValue = elements[index];
358 >    public E set(int index, E element) {
359 >        final ReentrantLock lock = this.lock;
360 >        lock.lock();
361 >        try {
362 >            Object[] elements = getArray();
363 >            int len = elements.length;
364 >            Object oldValue = elements[index];
365  
366 <        if (oldValue != element &&
367 <            (element == null || !element.equals(oldValue))) {
368 <            Object[] newElements = clone(elements, len);
369 <            newElements[index] = element;
370 <            setArray(newElements);
366 >            if (oldValue != element &&
367 >                (element == null || !element.equals(oldValue))) {
368 >                Object[] newElements = copyOf(elements, len);
369 >                newElements[index] = element;
370 >                setArray(newElements);
371 >            }
372 >            return (E)oldValue;
373 >        } finally {
374 >            lock.unlock();
375          }
359        return (E)oldValue;
376      }
377  
378      /**
# Line 365 | Line 381 | public class CopyOnWriteArrayList<E>
381       * @param e element to be appended to this list
382       * @return <tt>true</tt> (as per the spec for {@link Collection#add})
383       */
384 <    public synchronized boolean add(E e) {
385 <        Object[] elements = getArray();
386 <        int len = elements.length;
387 <        Object[] newElements = clone(elements, len + 1);
388 <        newElements[len] = e;
389 <        setArray(newElements);
384 >    public boolean add(E e) {
385 >        final ReentrantLock lock = this.lock;
386 >        lock.lock();
387 >        try {
388 >            Object[] elements = getArray();
389 >            int len = elements.length;
390 >            Object[] newElements = copyOf(elements, len + 1);
391 >            newElements[len] = e;
392 >            setArray(newElements);
393 >        } finally {
394 >            lock.unlock();
395 >        }
396          return true;
397      }
398  
# Line 381 | Line 403 | public class CopyOnWriteArrayList<E>
403       *
404       * @throws IndexOutOfBoundsException {@inheritDoc}
405       */
406 <    public synchronized void add(int index, E element) {
407 <        Object[] elements = getArray();
408 <        int len = elements.length;
409 <        if (index > len || index < 0)
410 <            throw new IndexOutOfBoundsException("Index: " + index+
411 <                                                ", Size: " + len);
412 <        Object[] newElements;
413 <        int numMoved = len - index;
414 <        if (numMoved == 0)
415 <            newElements = clone(elements, len + 1);
416 <        else {
417 <            newElements = new Object[len + 1];
418 <            System.arraycopy(elements, 0, newElements, 0, index);
419 <            System.arraycopy(elements, index, newElements, index + 1,
420 <                             numMoved);
406 >    public void add(int index, E element) {
407 >        final ReentrantLock lock = this.lock;
408 >        lock.lock();
409 >        try {
410 >            Object[] elements = getArray();
411 >            int len = elements.length;
412 >            if (index > len || index < 0)
413 >                throw new IndexOutOfBoundsException("Index: " + index+
414 >                                                    ", Size: " + len);
415 >            Object[] newElements;
416 >            int numMoved = len - index;
417 >            if (numMoved == 0)
418 >                newElements = copyOf(elements, len + 1);
419 >            else {
420 >                newElements = new Object[len + 1];
421 >                System.arraycopy(elements, 0, newElements, 0, index);
422 >                System.arraycopy(elements, index, newElements, index + 1,
423 >                                 numMoved);
424 >            }
425 >            newElements[index] = element;
426 >            setArray(newElements);
427 >        } finally {
428 >            lock.unlock();
429          }
400        newElements[index] = element;
401        setArray(newElements);
430      }
431  
432      /**
# Line 408 | Line 436 | public class CopyOnWriteArrayList<E>
436       *
437       * @throws IndexOutOfBoundsException {@inheritDoc}
438       */
439 <    public synchronized E remove(int index) {
440 <        Object[] elements = getArray();
441 <        int len = elements.length;
442 <        Object oldValue = elements[index];
443 <        int numMoved = len - index - 1;
444 <        if (numMoved == 0)
445 <            setArray(clone(elements, len - 1));
446 <        else {
447 <            Object[] newElements = new Object[len - 1];
448 <            System.arraycopy(elements, 0, newElements, 0, index);
449 <            System.arraycopy(elements, index + 1, newElements, index,
450 <                             numMoved);
451 <            setArray(newElements);
439 >    public E remove(int index) {
440 >        Object oldValue;
441 >        final ReentrantLock lock = this.lock;
442 >        lock.lock();
443 >        try {
444 >            Object[] elements = getArray();
445 >            int len = elements.length;
446 >            oldValue = elements[index];
447 >            int numMoved = len - index - 1;
448 >            if (numMoved == 0)
449 >                setArray(copyOf(elements, len - 1));
450 >            else {
451 >                Object[] newElements = new Object[len - 1];
452 >                System.arraycopy(elements, 0, newElements, 0, index);
453 >                System.arraycopy(elements, index + 1, newElements, index,
454 >                                 numMoved);
455 >                setArray(newElements);
456 >            }
457 >        } finally {
458 >            lock.unlock();
459          }
460          return (E)oldValue;
461      }
# Line 438 | Line 473 | public class CopyOnWriteArrayList<E>
473       * @param o element to be removed from this list, if present
474       * @return <tt>true</tt> if this list contained the specified element
475       */
476 <    public synchronized boolean remove(Object o) {
477 <        Object[] elements = getArray();
478 <        int len = elements.length;
479 <        if (len != 0) {
480 <            // Copy while searching for element to remove
481 <            // This wins in the normal case of element being present
482 <            int newlen = len - 1;
483 <            Object[] newElements = new Object[newlen];
484 <
485 <            for (int i = 0; i < newlen; ++i) {
486 <                if (o == elements[i] ||
487 <                    (o != null && o.equals(elements[i]))) {
488 <                    // found one;  copy remaining and exit
489 <                    for (int k = i + 1; k < len; ++k)
490 <                        newElements[k - 1] = elements[k];
476 >    public boolean remove(Object o) {
477 >        final ReentrantLock lock = this.lock;
478 >        lock.lock();
479 >        try {
480 >            Object[] elements = getArray();
481 >            int len = elements.length;
482 >            if (len != 0) {
483 >                // Copy while searching for element to remove
484 >                // This wins in the normal case of element being present
485 >                int newlen = len - 1;
486 >                Object[] newElements = new Object[newlen];
487 >
488 >                for (int i = 0; i < newlen; ++i) {
489 >                    if (o == elements[i] ||
490 >                        (o != null && o.equals(elements[i]))) {
491 >                        // found one;  copy remaining and exit
492 >                        for (int k = i + 1; k < len; ++k)
493 >                            newElements[k - 1] = elements[k];
494 >                        setArray(newElements);
495 >                        return true;
496 >                    } else
497 >                        newElements[i] = elements[i];
498 >                }
499 >
500 >                // special handling for last cell
501 >                if (o == elements[newlen] ||
502 >                    (o != null && o.equals(elements[newlen]))) {
503                      setArray(newElements);
504                      return true;
505 <                } else
459 <                    newElements[i] = elements[i];
460 <            }
461 <
462 <            // special handling for last cell
463 <            if (o == elements[newlen] ||
464 <                (o != null && o.equals(elements[newlen]))) {
465 <                setArray(newElements);
466 <                return true;
505 >                }
506              }
507 +            return false;
508 +        } finally {
509 +            lock.unlock();
510          }
469        return false;
511      }
512  
513      /**
# Line 482 | Line 523 | public class CopyOnWriteArrayList<E>
523       *              range (fromIndex &lt; 0 || fromIndex &gt;= size() || toIndex
524       *              &gt; size() || toIndex &lt; fromIndex)
525       */
526 <    private synchronized void removeRange(int fromIndex, int toIndex) {
527 <        Object[] elements = getArray();
528 <        int len = elements.length;
526 >    private void removeRange(int fromIndex, int toIndex) {
527 >        final ReentrantLock lock = this.lock;
528 >        lock.lock();
529 >        try {
530 >            Object[] elements = getArray();
531 >            int len = elements.length;
532  
533 <        if (fromIndex < 0 || fromIndex >= len ||
534 <            toIndex > len || toIndex < fromIndex)
535 <            throw new IndexOutOfBoundsException();
536 <        int newlen = len - (toIndex - fromIndex);
537 <        int numMoved = len - toIndex;
538 <        if (numMoved == 0)
539 <            setArray(clone(elements, newlen));
540 <        else {
541 <            Object[] newElements = new Object[newlen];
542 <            System.arraycopy(elements, 0, newElements, 0, fromIndex);
543 <            System.arraycopy(elements, toIndex, newElements,
544 <                             fromIndex, numMoved);
545 <            setArray(newElements);
533 >            if (fromIndex < 0 || fromIndex >= len ||
534 >                toIndex > len || toIndex < fromIndex)
535 >                throw new IndexOutOfBoundsException();
536 >            int newlen = len - (toIndex - fromIndex);
537 >            int numMoved = len - toIndex;
538 >            if (numMoved == 0)
539 >                setArray(copyOf(elements, newlen));
540 >            else {
541 >                Object[] newElements = new Object[newlen];
542 >                System.arraycopy(elements, 0, newElements, 0, fromIndex);
543 >                System.arraycopy(elements, toIndex, newElements,
544 >                                 fromIndex, numMoved);
545 >                setArray(newElements);
546 >            }
547 >        } finally {
548 >            lock.unlock();
549          }
550      }
551  
# Line 508 | Line 555 | public class CopyOnWriteArrayList<E>
555       * @param e element to be added to this list, if absent
556       * @return <tt>true</tt> if the element was added
557       */
558 <    public synchronized boolean addIfAbsent(E e) {
559 <        // Copy while checking if already present.
560 <        // This wins in the most common case where it is not present
561 <        Object[] elements = getArray();
562 <        int len = elements.length;
563 <        Object[] newElements = new Object[len + 1];
564 <        for (int i = 0; i < len; ++i) {
565 <            if (e == elements[i] || (e != null && e.equals(elements[i])))
566 <                return false; // exit, throwing away copy
567 <            else
568 <                newElements[i] = elements[i];
558 >    public boolean addIfAbsent(E e) {
559 >        final ReentrantLock lock = this.lock;
560 >        lock.lock();
561 >        try {
562 >            // Copy while checking if already present.
563 >            // This wins in the most common case where it is not present
564 >            Object[] elements = getArray();
565 >            int len = elements.length;
566 >            Object[] newElements = new Object[len + 1];
567 >            for (int i = 0; i < len; ++i) {
568 >                if (e == elements[i] || (e != null && e.equals(elements[i])))
569 >                    return false; // exit, throwing away copy
570 >                else
571 >                    newElements[i] = elements[i];
572 >            }
573 >            newElements[len] = e;
574 >            setArray(newElements);
575 >            return true;
576 >        } finally {
577 >            lock.unlock();
578          }
523        newElements[len] = e;
524        setArray(newElements);
525        return true;
579      }
580  
581      /**
# Line 559 | Line 612 | public class CopyOnWriteArrayList<E>
612       *         or if the specified collection is null
613       * @see #remove(Object)
614       */
615 <    public synchronized boolean removeAll(Collection<?> c) {
616 <        Object[] elements = getArray();
617 <        int len = elements.length;
618 <        if (len != 0) {
619 <            // temp array holds those elements we know we want to keep
620 <            int newlen = 0;
621 <            Object[] temp = new Object[len];
622 <            for (int i = 0; i < len; ++i) {
623 <                Object element = elements[i];
624 <                if (!c.contains(element))
625 <                    temp[newlen++] = element;
626 <            }
627 <            if (newlen != len) {
628 <                setArray(cloneRange(temp, 0, newlen, Object[].class));
629 <                return true;
615 >    public boolean removeAll(Collection<?> c) {
616 >        final ReentrantLock lock = this.lock;
617 >        lock.lock();
618 >        try {
619 >            Object[] elements = getArray();
620 >            int len = elements.length;
621 >            if (len != 0) {
622 >                // temp array holds those elements we know we want to keep
623 >                int newlen = 0;
624 >                Object[] temp = new Object[len];
625 >                for (int i = 0; i < len; ++i) {
626 >                    Object element = elements[i];
627 >                    if (!c.contains(element))
628 >                        temp[newlen++] = element;
629 >                }
630 >                if (newlen != len) {
631 >                    setArray(copyOfRange(temp, 0, newlen, Object[].class));
632 >                    return true;
633 >                }
634              }
635 +            return false;
636 +        } finally {
637 +            lock.unlock();
638          }
579        return false;
639      }
640  
641      /**
# Line 593 | Line 652 | public class CopyOnWriteArrayList<E>
652       *         or if the specified collection is null
653       * @see #remove(Object)
654       */
655 <    public synchronized boolean retainAll(Collection<?> c) {
656 <        Object[] elements = getArray();
657 <        int len = elements.length;
658 <        if (len != 0) {
659 <            int newlen = 0;
660 <            Object[] temp = new Object[len];
661 <            for (int i = 0; i < len; ++i) {
662 <                Object element = elements[i];
663 <                if (c.contains(element))
664 <                    temp[newlen++] = element;
665 <            }
666 <            if (newlen != len) {
667 <                setArray(cloneRange(temp, 0, newlen, Object[].class));
668 <                return true;
655 >    public boolean retainAll(Collection<?> c) {
656 >        final ReentrantLock lock = this.lock;
657 >        lock.lock();
658 >        try {
659 >            Object[] elements = getArray();
660 >            int len = elements.length;
661 >            if (len != 0) {
662 >                int newlen = 0;
663 >                Object[] temp = new Object[len];
664 >                for (int i = 0; i < len; ++i) {
665 >                    Object element = elements[i];
666 >                    if (c.contains(element))
667 >                        temp[newlen++] = element;
668 >                }
669 >                if (newlen != len) {
670 >                    setArray(copyOfRange(temp, 0, newlen, Object[].class));
671 >                    return true;
672 >                }
673              }
674 +            return false;
675 +        } finally {
676 +            lock.unlock();
677          }
612        return false;
678      }
679  
680      /**
# Line 623 | Line 688 | public class CopyOnWriteArrayList<E>
688       * @throws NullPointerException if the specified collection is null
689       * @see #addIfAbsent(Object)
690       */
691 <    public synchronized int addAllAbsent(Collection<? extends E> c) {
691 >    public int addAllAbsent(Collection<? extends E> c) {
692          int added = 0;
693 <        int numNew = c.size();
694 <        if (numNew != 0) {
695 <            Object[] elements = getArray();
696 <            int len = elements.length;
697 <
698 <            Object[] temp = new Object[numNew];
699 <            for (E e : c) {
700 <                if (indexOf(e, elements, 0, len) < 0 &&
701 <                    indexOf(e, temp, 0, added) < 0)
702 <                    temp[added++] = e;
703 <            }
704 <            if (added != 0) {
705 <                Object[] newElements = new Object[len + added];
706 <                System.arraycopy(elements, 0, newElements, 0, len);
707 <                System.arraycopy(temp, 0, newElements, len, added);
708 <                setArray(newElements);
693 >        final ReentrantLock lock = this.lock;
694 >        lock.lock();
695 >        try {
696 >            int numNew = c.size();
697 >            if (numNew != 0) {
698 >                Object[] elements = getArray();
699 >                int len = elements.length;
700 >
701 >                Object[] temp = new Object[numNew];
702 >                for (E e : c) {
703 >                    if (indexOf(e, elements, 0, len) < 0 &&
704 >                        indexOf(e, temp, 0, added) < 0)
705 >                        temp[added++] = e;
706 >                }
707 >                if (added != 0) {
708 >                    Object[] newElements = new Object[len + added];
709 >                    System.arraycopy(elements, 0, newElements, 0, len);
710 >                    System.arraycopy(temp, 0, newElements, len, added);
711 >                    setArray(newElements);
712 >                }
713              }
714 +        } finally {
715 +            lock.unlock();
716          }
717          return added;
718      }
# Line 650 | Line 721 | public class CopyOnWriteArrayList<E>
721       * Removes all of the elements from this list.
722       * The list will be empty after this call returns.
723       */
724 <    public synchronized void clear() {
725 <        setArray(new Object[0]);
724 >    public void clear() {
725 >        final ReentrantLock lock = this.lock;
726 >        lock.lock();
727 >        try { setArray(new Object[0]); }
728 >        finally { lock.unlock(); }
729      }
730  
731      /**
# Line 664 | Line 738 | public class CopyOnWriteArrayList<E>
738       * @throws NullPointerException if the specified collection is null
739       * @see #add(Object)
740       */
741 <    public synchronized boolean addAll(Collection<? extends E> c) {
741 >    public boolean addAll(Collection<? extends E> c) {
742          int numNew = c.size();
743          if (numNew == 0)
744              return false;
745 <
746 <        Object[] elements = getArray();
747 <        int len = elements.length;
748 <        Object[] newElements = new Object[len + numNew];
749 <        System.arraycopy(elements, 0, newElements, 0, len);
750 <        for (E e : c)
751 <            newElements[len++] = e;
752 <        setArray(newElements);
745 >        final ReentrantLock lock = this.lock;
746 >        lock.lock();
747 >        try {
748 >            Object[] elements = getArray();
749 >            int len = elements.length;
750 >            Object[] newElements = new Object[len + numNew];
751 >            System.arraycopy(elements, 0, newElements, 0, len);
752 >            for (E e : c)
753 >                newElements[len++] = e;
754 >            setArray(newElements);
755 >        } finally {
756 >            lock.unlock();
757 >        }
758          return true;
759      }
760  
# Line 695 | Line 774 | public class CopyOnWriteArrayList<E>
774       * @throws NullPointerException if the specified collection is null
775       * @see #add(int,Object)
776       */
777 <    public synchronized boolean addAll(int index, Collection<? extends E> c) {
699 <        Object[] elements = getArray();
700 <        int len = elements.length;
701 <        if (index > len || index < 0)
702 <            throw new IndexOutOfBoundsException("Index: " + index +
703 <                                                ", Size: "+ len);
777 >    public boolean addAll(int index, Collection<? extends E> c) {
778          int numNew = c.size();
779 <        if (numNew == 0)
780 <            return false;
781 <        int numMoved = len - index;
782 <        Object[] newElements;
783 <        if (numMoved == 0)
784 <            newElements = clone(elements, len + numNew);
785 <        else {
786 <            newElements = new Object[len + numNew];
787 <            System.arraycopy(elements, index, newElements,
788 <                             index + numNew, numMoved);
789 <            System.arraycopy(elements, index, newElements,
790 <                             index + numNew, numMoved);
779 >        final ReentrantLock lock = this.lock;
780 >        lock.lock();
781 >        try {
782 >            Object[] elements = getArray();
783 >            int len = elements.length;
784 >            if (index > len || index < 0)
785 >                throw new IndexOutOfBoundsException("Index: " + index +
786 >                                                    ", Size: "+ len);
787 >            if (numNew != 0) {
788 >                int numMoved = len - index;
789 >                Object[] newElements;
790 >                if (numMoved == 0)
791 >                    newElements = copyOf(elements, len + numNew);
792 >                else {
793 >                    newElements = new Object[len + numNew];
794 >                    System.arraycopy(elements, index, newElements,
795 >                                     index + numNew, numMoved);
796 >                    System.arraycopy(elements, index, newElements,
797 >                                     index + numNew, numMoved);
798 >                }
799 >                for (E e : c)
800 >                    newElements[index++] = e;
801 >                setArray(newElements);
802 >            }
803 >        } finally {
804 >            lock.unlock();
805          }
806 <        for (E e : c)
719 <            newElements[index++] = e;
720 <        setArray(newElements);
721 <
722 <        return true;
806 >        return numNew != 0;
807      }
808  
809      /**
# Line 756 | Line 840 | public class CopyOnWriteArrayList<E>
840          // Read in size, and any hidden stuff
841          s.defaultReadObject();
842  
843 +        // bind to new lock
844 +        resetLock();
845 +
846          // Read in array length and allocate array
847          int len = s.readInt();
848          Object[] elements = new Object[len];
# Line 764 | Line 851 | public class CopyOnWriteArrayList<E>
851          for (int i = 0; i < len; i++)
852              elements[i] = s.readObject();
853          setArray(elements);
854 +
855      }
856  
857      /**
# Line 971 | Line 1059 | public class CopyOnWriteArrayList<E>
1059       * @return a view of the specified range within this list
1060       * @throws IndexOutOfBoundsException {@inheritDoc}
1061       */
1062 <    public synchronized List<E> subList(int fromIndex, int toIndex) {
1063 <        // synchronized since sublist constructor depends on it.
1064 <        Object[] elements = getArray();
1065 <        int len = elements.length;
1066 <        if (fromIndex < 0 || toIndex > len  || fromIndex > toIndex)
1067 <            throw new IndexOutOfBoundsException();
1068 <        return new COWSubList<E>(this, fromIndex, toIndex);
1062 >    public List<E> subList(int fromIndex, int toIndex) {
1063 >        final ReentrantLock lock = this.lock;
1064 >        lock.lock();
1065 >        try {
1066 >            Object[] elements = getArray();
1067 >            int len = elements.length;
1068 >            if (fromIndex < 0 || toIndex > len  || fromIndex > toIndex)
1069 >                throw new IndexOutOfBoundsException();
1070 >            return new COWSubList<E>(this, fromIndex, toIndex);
1071 >        } finally {
1072 >            lock.unlock();
1073 >        }
1074      }
1075  
983    private static class COWSubList<E> extends AbstractList<E> {
984        /*
985          This class extends AbstractList merely for convenience, to
986          avoid having to define addAll, etc. This doesn't hurt, but
987          is wasteful.  This class does not need or use modCount
988          mechanics in AbstractList, but does need to check for
989          concurrent modification using similar mechanics.  On each
990          operation, the array that we expect the backing list to use
991          is checked and updated.  Since we do this for all of the
992          base operations invoked by those defined in AbstractList,
993          all is well.  While inefficient, this is not worth
994          improving.  The kinds of list operations inherited from
995          AbstractList are already so slow on COW sublists that
996          adding a bit more space/time doesn't seem even noticeable.
997        */
1076  
1077 +    /**
1078 +     * Sublist for CopyOnWriteArrayList.
1079 +     * This class extends AbstractList merely for convenience, to
1080 +     * avoid having to define addAll, etc. This doesn't hurt, but
1081 +     * is wasteful.  This class does not need or use modCount
1082 +     * mechanics in AbstractList, but does need to check for
1083 +     * concurrent modification using similar mechanics.  On each
1084 +     * operation, the array that we expect the backing list to use
1085 +     * is checked and updated.  Since we do this for all of the
1086 +     * base operations invoked by those defined in AbstractList,
1087 +     * all is well.  While inefficient, this is not worth
1088 +     * improving.  The kinds of list operations inherited from
1089 +     * AbstractList are already so slow on COW sublists that
1090 +     * adding a bit more space/time doesn't seem even noticeable.
1091 +     */
1092 +    private static class COWSubList<E> extends AbstractList<E> {
1093          private final CopyOnWriteArrayList<E> l;
1094          private final int offset;
1095          private int size;
# Line 1023 | Line 1117 | public class CopyOnWriteArrayList<E>
1117          }
1118  
1119          public E set(int index, E element) {
1120 <            synchronized(l) {
1120 >            ReentrantLock lock = l.lock;
1121 >            lock.lock();
1122 >            try {
1123                  rangeCheck(index);
1124                  checkForComodification();
1125                  E x = l.set(index + offset, element);
1126                  expectedArray = l.getArray();
1127                  return x;
1128 +            } finally {
1129 +                lock.unlock();
1130              }
1131          }
1132  
1133          public E get(int index) {
1134 <            synchronized(l) {
1134 >            ReentrantLock lock = l.lock;
1135 >            lock.lock();
1136 >            try {
1137                  rangeCheck(index);
1138                  checkForComodification();
1139                  return l.get(index + offset);
1140 +            } finally {
1141 +                lock.unlock();
1142              }
1143          }
1144  
1145          public int size() {
1146 <            synchronized(l) {
1146 >            ReentrantLock lock = l.lock;
1147 >            lock.lock();
1148 >            try {
1149                  checkForComodification();
1150                  return size;
1151 +            } finally {
1152 +                lock.unlock();
1153              }
1154          }
1155  
1156          public void add(int index, E element) {
1157 <            synchronized(l) {
1157 >            ReentrantLock lock = l.lock;
1158 >            lock.lock();
1159 >            try {
1160                  checkForComodification();
1161                  if (index<0 || index>size)
1162                      throw new IndexOutOfBoundsException();
1163                  l.add(index + offset, element);
1164                  expectedArray = l.getArray();
1165                  size++;
1166 +            } finally {
1167 +                lock.unlock();
1168              }
1169          }
1170  
1171          public void clear() {
1172 <            synchronized(l) {
1172 >            ReentrantLock lock = l.lock;
1173 >            lock.lock();
1174 >            try {
1175                  checkForComodification();
1176                  l.removeRange(offset, offset+size);
1177                  expectedArray = l.getArray();
1178                  size = 0;
1179 +            } finally {
1180 +                lock.unlock();
1181              }
1182          }
1183  
1184          public E remove(int index) {
1185 <            synchronized(l) {
1185 >            ReentrantLock lock = l.lock;
1186 >            lock.lock();
1187 >            try {
1188                  rangeCheck(index);
1189                  checkForComodification();
1190                  E result = l.remove(index + offset);
1191                  expectedArray = l.getArray();
1192                  size--;
1193                  return result;
1194 +            } finally {
1195 +                lock.unlock();
1196              }
1197          }
1198  
1199          public Iterator<E> iterator() {
1200 <            synchronized(l) {
1200 >            ReentrantLock lock = l.lock;
1201 >            lock.lock();
1202 >            try {
1203                  checkForComodification();
1204                  return new COWSubListIterator<E>(l, 0, offset, size);
1205 +            } finally {
1206 +                lock.unlock();
1207              }
1208          }
1209  
1210          public ListIterator<E> listIterator(final int index) {
1211 <            synchronized(l) {
1211 >            ReentrantLock lock = l.lock;
1212 >            lock.lock();
1213 >            try {
1214                  checkForComodification();
1215                  if (index<0 || index>size)
1216                      throw new IndexOutOfBoundsException("Index: "+index+
1217                                                          ", Size: "+size);
1218                  return new COWSubListIterator<E>(l, index, offset, size);
1219 +            } finally {
1220 +                lock.unlock();
1221              }
1222          }
1223  
1224          public List<E> subList(int fromIndex, int toIndex) {
1225 <            synchronized(l) {
1225 >            ReentrantLock lock = l.lock;
1226 >            lock.lock();
1227 >            try {
1228                  checkForComodification();
1229                  if (fromIndex<0 || toIndex>size)
1230                      throw new IndexOutOfBoundsException();
1231                  return new COWSubList<E>(l, fromIndex + offset,
1232                                           toIndex + offset);
1233 +            } finally {
1234 +                lock.unlock();
1235              }
1236          }
1237  
# Line 1164 | Line 1294 | public class CopyOnWriteArrayList<E>
1294          }
1295      }
1296  
1297 +    // Support for resetting lock while deserializing
1298 +    private static final Unsafe unsafe =  Unsafe.getUnsafe();
1299 +    private static final long lockOffset;
1300 +    static {
1301 +        try {
1302 +            lockOffset = unsafe.objectFieldOffset
1303 +                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
1304 +            } catch (Exception ex) { throw new Error(ex); }
1305 +    }
1306 +    private void resetLock() {
1307 +        unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock());
1308 +    }
1309 +
1310 +
1311      // Temporary emulations of anticipated new j.u.Arrays functions
1312  
1313 <    private static <T,U> T[] cloneRange(U[] original, int from, int to,
1313 >    private static <T,U> T[] copyOfRange(U[] original, int from, int to,
1314                                          Class<? extends T[]> newType) {
1315          int newLength = to - from;
1316          if (newLength < 0)
# Line 1178 | Line 1322 | public class CopyOnWriteArrayList<E>
1322          return copy;
1323      }
1324  
1325 <    private static <T,U> T[] clone(U[] original, int newLength,
1325 >    private static <T,U> T[] copyOf(U[] original, int newLength,
1326                                     Class<? extends T[]> newType) {
1327          T[] copy = (T[]) java.lang.reflect.Array.newInstance
1328              (newType.getComponentType(), newLength);
# Line 1187 | Line 1331 | public class CopyOnWriteArrayList<E>
1331          return copy;
1332      }
1333  
1334 <    private static <T> T[] clone(T[] original, int newLength) {
1335 <        return (T[]) clone(original, newLength, original.getClass());
1334 >    private static <T> T[] copyOf(T[] original, int newLength) {
1335 >        return (T[]) copyOf(original, newLength, original.getClass());
1336      }
1193
1337   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines