• ArrayList学习总结


    1.ArrayList简介[1]

    ArrayList实现了List接口。ArrayList的方法实现和vector相似,只是线程不安全的。

    ArrayList的 size、isEmpty、get、set、iterator等方法的时间复杂度为O(1),add n个元素需要O(n)的时间(add一个元素的时间摊销成本是O(1)),其它方法的运行时间多为线性的。比如remove(int index)的时间复杂度是O(n);remove(Object obj)的时间复杂度是O(n),removeAll的时间复杂度是O(n)。

    ArrayList的初始容量是10,扩容机制是oldCapacity+oldCapacity>>1,add一个元素的时间摊销成本是常量。

    ArrayList是线程不安全的。当多个线程同时操作ArrayList时,且至少一个线程对ArrayList进行结构性修改时,可能出现线程不安全。需要采取一些策略以确保线程安全,具体详见第3节。

    使用iterator()或listIterator(int index)获取的迭代器,是fail-fast的;如果使用了迭代器类之外的方法对list进行结构性修改(remove/add/clear等),再调用迭代器的方法将会抛出异常。这避免了在将来某个不确定的时间出现线程安全问题。

    2.使用ArrayList的注意事项[2]

    1)如果元素是引用类型,使用remove/removeAll,contains/retainAll前,需要重写元素的equals()方法,重写equals前,需要重写hashcode方法。因为这些方法的底层都调用了equals方法。

    2)不要在for(Element e:list)循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁(如果使用的List类未加锁,需要开发者自己加锁)。

    在for(Element e:list)里进行元素的add/remove/clear操作时会报错,如图1。报错的的原因是for(Element e:list)的底层是迭代器(如图2)。使用迭代器时,如果使用了迭代器类之外的方法对list进行结构性修改(remove/add/clear等),会有fail-fast的机制,如图3。迭代器的fail-fast是指在使用迭代器遍历时,如果使用了迭代器类之外的方法对list进行结构性修改(remove/add/clear等),则使用迭代器的遍历将终止,并抛出异常ConcurrentModificationException。

    public class ArrayListStudy1 {
        //forEach中使用add/remove方法
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<Integer>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            for(Integer i:list){
                if(1==i){
                    list.remove(1);
                }
            }
        }
    }
    
    运行报错:
    Exception in thread "main" java.util.ConcurrentModificationException
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    	at java.util.ArrayList$Itr.next(ArrayList.java:859)
    	at com.study.collection.ArrayListStudy2.main(ArrayListStudy2.java:15)
    

    图1 在for(Element e:list)里进行元素的add/remove/clear操作

    反编译得到以下代码:

    Iterator<Integer> it = list.iterator();
    while (it.hasNext()) {
        Integer i = it.next();
        if (1 == i.intValue()) {
            list.remove(1);
        }
    }
    

    图2 图1代码反编译后的代码(反编译工具jadx-gui-1.3.3-1)

    查看迭代器的源码:

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }
    
     private class Itr implements Iterator<E> {
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                //如果使用了Iterator类之外的方法对list进行结构性修改(remove/add/clear等),则抛出异常(fail-fast)
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
     }
    

    ArrayList类注释中对fail-fast的详细注释:

    /**
     * <p><a name="fail-fast">
     * The iterators returned by this class's {@link #iterator() iterator} and
     * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
     * if the list is structurally modified at any time after the iterator is
     * created, in any way except through the iterator's own
     * {@link ListIterator#remove() remove} or
     * {@link ListIterator#add(Object) add} methods, the iterator will throw a
     * {@link ConcurrentModificationException}.  Thus, in the face of
     * concurrent modification, the iterator fails quickly and cleanly, rather
     * than risking arbitrary, non-deterministic behavior at an undetermined
     * time in the future.
    */ 
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    }
    

    3)SubList是ArrayList的视图,它拥有ArrayList相同的方法;但SubList不是ArrayList类或子类,它是ArrayList的内部类,不能将SubList强转为ArrayList类型。如果将SubList强转为ArrayList,则会报错,如图3。所有对ArrayList的非结构性(非add/remove/clear)的操作,subList也会相应变化,反之亦然。如果使用了SubList类之外的方法对list进行结构性修改(remove/add/clear等),对subList的所有操作都会报错。这类似于第二条中的fail-fast机制。

    如果使用了SubList类之外的方法对list进行结构性修改(remove/add/clear等),对subList的所有操作都会报错。subList的常用方法如图4所示。在这些方法中都有 checkForComodification()方法,在单线程中,这个方法会判断ArrayList是否有通过了SubList类之外的方法对list进行结构性修改(remove/add/clear等),如果有,则会抛出异常ConcurrentModificationException。

    public class ArrayListStudy2 {
        public static void main(String[] args) {
            CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            ArrayList list = (ArrayList) list.subList(0, 3);
        }
    }
    运行报错:
    Exception in thread "main" java.lang.ClassCastException: java.util.concurrent.CopyOnWriteArrayList$COWSubList cannot be cast to java.util.ArrayList
    	at com.study.collection.ArrayListStudy2.main(ArrayListStudy2.java:17)
    

    图3 SubList强转为ArrayList运行报错

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private class SubList extends AbstractList<E> implements RandomAccess {
            public E get(int index) {
                rangeCheck(index);
                checkForComodification();
                return ArrayList.this.elementData(offset + index);
            }
    
            public void add(int index, E e) {
                rangeCheckForAdd(index);
                checkForComodification();
                parent.add(parentOffset + index, e);
                this.modCount = parent.modCount;
                this.size++;
            }
            
            private void checkForComodification() {
                if (ArrayList.this.modCount != this.modCount)
                    throw new ConcurrentModificationException();
        	}
        }
    }
    

    图4 SubList的常用方法

    4)toArray()方法后,进行类型转换会报错,如图5。这是因为toArray()得到的数组是Object[]类型,不能强转为Integer[]。应使用toArray(T[] a)方法。

    public class ArrayListStudy4 {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            Integer[] objs = (Integer[])list.toArray();
            //使用toArray(T[] a)方法
            //Integer[] integers1 = list.toArray(new Integer[list.size()]);
        }
    }
    报错:
    Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
    	at com.study.collection.ArrayListStudy4.main(ArrayListStudy4.java:13)
    

    图5 list.toArray()后类型强转报错

    Array.asList(T... a)返回的类型时Arrays的内部类ArrayList,没有实现add/remove/clear等方法;如果使用返回的对象调用add等方法,则会报错,如图6所示。

    public class ArrayListStudy4 {
        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(new Integer[]{1,2,3});
            list.add(4);
        }
    }
    报错:
    Exception in thread "main" java.lang.UnsupportedOperationException
    	at java.util.AbstractList.add(AbstractList.java:148)
    	at java.util.AbstractList.add(AbstractList.java:108)
    	at com.study.collection.ArrayListStudy4.main(ArrayListStudy4.java:10)
    

    图6 Array.asList(T... a)返回的值使用add方法报错

    Array.asList(T... a)的源码如下图7所示。

    public class Arrays {	
        @SafeVarargs
            @SuppressWarnings("varargs")
            public static <T> List<T> asList(T... a) {
                return new ArrayList<>(a);
            }
    
            /**
             * @serial include
             */
            private static class ArrayList<E> extends AbstractList<E>
                implements RandomAccess, java.io.Serializable
            {
                //没有实现add/remove/clear等方法
            }
    }
    

    图7 Array.asList(T... a)的源码

    5)泛型通配符<? entends T>来接受返回的数据,此写法的泛型集合不能使用add方法,而<? super T>不能使用get方法,作为接口调用赋值时易出错。如图8所示,<? entends T>写法的泛型集合使用add方法报错,<? super T>写法的泛型使用get方法出错。

    public class ArrayListStudy4 {
        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(new Integer[]{1,2,3});
            list.add(4);
    		
            ArrayList<? extends Student> students = new ArrayList<Student>();
            //运行报错
            students.add(null);
    
            ArrayList<? super Student> students2 = new ArrayList<Student>();
            students2.add(new Student());
            //运行报错
            Object object = students2.get(0);
        }
    }
    
    报错:
    Exception in thread "main" java.lang.UnsupportedOperationException
    	at java.util.AbstractList.add(AbstractList.java:148)
    	at java.util.AbstractList.add(AbstractList.java:108)
    	at com.study.collection.ArrayListStudy4.main(ArrayListStudy4.java:12)
    

    图8 <? entends T>写法的泛型集合使用add方法报错,<? super T>写法使用get方法报错

    6)在JDK7版本及以上,Comparator实现类要满足如下三个条件,不然Arrays.sort,Collections.sort会报IllegalArgumentException异常。三个条件如下:

    a)x,y的比较结果和y,x的比较结果相反;

    b) x>y,y>z,则x>z;

    c)x=y,则x,z比较结果和y,z比较结果相同;

    7)集合泛型定义时,在JDK7以上,使用diamond语法或全省略。

    说明:菱形泛型,即diamond,直接使用<>来指代前面已经指定的类型。

    //<>diamond方式
    HashMap<String,String> userCache = new HashMap<>(16);
    //全省略方式
    ArrayList<User> users = new ArrayList(10);
    

    3.ArrayList的线程安全

    ArrayList的线程安全是指在并发操作ArrayList时,操作的结果是否会达到人们期望的效果。通常线程安全的方法是通过synchronized来保证原子性,可见性和顺序性,也就是要as-if-serial语义。如果没有考虑到代码中执行的原子性,这就可能会出现线程不安全的问题。

    比如ArrayList就是线程不安全的。线程不安全的场景主要包括以下几种。

    3.1 add方法

    如图9多线程并发调用add()方法时,可能会出现图10和11的两种异常情况,一种是抛出ArrayIndexOutOfBoundsException的异常,另一种是ArrayList有些索引没有存入值(为null)。

    public class ArrayListStudy {
        public static ArrayList arrayList = new ArrayList();
        //并发处理
        public static void main(String[] args) {
            ArrayList<Integer> str = new ArrayList<>();
            Thread[] threadArr = new Thread[1000];
            for(int i = 0;i<threadArr.length;i++){
                //新建一个线程
                threadArr[i] = new ArrayListThread();
                //线程启动
                threadArr[i].start();
            }
    
            for(int i=0;i<threadArr.length;i++){
                try {
                    threadArr[i].join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            for(int i=0;i<arrayList.size();i++){
                System.out.println(arrayList.get(i));
            }
        }
    }
    
    class ArrayListThread extends Thread{
        @Override
        public void run(){
            try{
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ArrayListStudy.arrayList.add(Thread.currentThread().getName());
        }
    }
    

    图9 多线程并发调用add()方法

    图10 并发调用add()方法时,出现数组越界异常(ArrayIndexOutOfBoundsException)的场景

    图11 并发调用add()方法时,索引没有存入值的场景

    3.2 remove方法

    remove()可能出现集合某些索引的值没有移除的场景。

    3.3 clone方法

    如图12所示,clone()方法是对原list的浅拷贝,对list中的元素进行了浅拷贝,如果元素是对象,只拷贝元素的地址。拷贝的时候会调用Arrays.copyOf(elementData,size)方法,拷贝的时候有读取原数组元素的操作,是线程不安全的。

    /**
         * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
         * elements themselves are not copied.)
         *
         * @return a clone of this <tt>ArrayList</tt> instance
         */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
    

    图12 ArrayList的clone()方法

    3.4 iterator方法

    iterator()获取的是ArrayList的内部类Itr。如图13所示,类Itr的next、previous、add、remove等方法是线程不安全的。且在使用iterator遍历时,如果使用了Iterator类之外的方法对list进行结构性修改(remove/add/clear等),则会抛出ConcurrentModificationException的异常;即fail-fast机制。

    private class Itr implements Iterator<E> {
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            int expectedModCount = modCount;
    
            Itr() {}
    
            public boolean hasNext() {
                return cursor != size;
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
    }
    

    图13 ArrayList的内部类Itr

    3.5 sublist方法

    sublist()获取的是ArrayList内部类SubList的实例,如图14所示。它的set、get、add等方法是线程不安全的。

     private class SubList extends AbstractList<E> implements RandomAccess {
            public E set(int index, E e) {
                rangeCheck(index);
                checkForComodification();
                E oldValue = ArrayList.this.elementData(offset + index);
                ArrayList.this.elementData[offset + index] = e;
                return oldValue;
            }
    
            public E get(int index) {
                rangeCheck(index);
                checkForComodification();
                return ArrayList.this.elementData(offset + index);
            }
    
            public void add(int index, E e) {
                rangeCheckForAdd(index);
                checkForComodification();
                parent.add(parentOffset + index, e);
                this.modCount = parent.modCount;
                this.size++;
            }
     }
    

    图14 ArrayList内部类SubList

    3.6 方法组合

    方法组合是指对操作List的元素方法的组合。我以两种情况为例。一种情况(后文使用“组合一”引用)是ArrayList的get与迭代器中的remove方法的组合;另一种情况(后文使用“组合二”引用)是ArrayList的get与SubList的add方法的组合。由于ArrayList没有采取任何线程安全的策略,当然这两种情况都是线程不安全的。

    3.7 线程安全的措施

    ArrayList是线程不安全的,ArrayList的方法没有添加任何措施以保证线程安全。ArrayList只适用于单线程的场景。在多线程下,通常使用下述的3种方式来实现线程安全。

    3.7.1 Vector

    Vector(已废弃)的方法实现和ArrayList类似,只是是线程安全的[3]。如图15,Vector线程安全的策略是通过在方法上添加synchronized关键字来实现的。Vector的iterator方法获取内部类Itr,该类中的方法是线程安全的。Vector的subList方法获取SynchronizedList类,该类中的方法是线程安全的。但由于内部类Itr中remove方法使用的锁对象是Vector.this,与ArrayList.get方法使用的锁对象this不同,因此组合一是线程不安全的。如图16,subList方法的返回值SynchronizedList中的方法使用的锁对象是当前的Vector实例,与ArrayList.get方法的锁对象相同,因此组合二是线程安全的。

    public class Vector<E>
        extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    	//锁对象this
    	public synchronized E get(int index) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            return elementData(index);
        }
        public synchronized Iterator<E> iterator() {
            return new Itr();
        }
        private class Itr implements Iterator<E> {
        	 public void remove() {
                if (lastRet == -1)
                    throw new IllegalStateException();
    		   //锁对象Vector.this                
                synchronized (Vector.this) {
                    checkForComodification();
                    Vector.this.remove(lastRet);
                    expectedModCount = modCount;
                }
                cursor = lastRet;
                lastRet = -1;
            }
        }
        public synchronized List<E> subList(int fromIndex, int toIndex) {
            return Collections.synchronizedList(super.subList(fromIndex, toIndex),
                                                this);
        }
    }
    

    图15 Vector类中的get、iterator、subList方法

    public class Collections {
        static class SynchronizedList<E>
            extends SynchronizedCollection<E>
            implements List<E> {
            
            SynchronizedList(List<E> list, Object mutex) {
                super(list, mutex);
                this.list = list;
            }
            public void add(int index, E element) {
                //锁对象为当前的Vector实例
                synchronized (mutex) {list.add(index, element);}
            }
        }
        
        static class SynchronizedCollection<E> implements Collection<E>, Serializable {
            SynchronizedCollection(Collection<E> c, Object mutex) {
                this.c = Objects.requireNonNull(c);
                this.mutex = Objects.requireNonNull(mutex);
            }
        }
    }
    

    图16 Collections.SynchronizedList中的方法

    3.7.2 Collections.synchronizedList(ArrayList list)

    可以通过Collections.synchronizedList(ArrayList list)方法实现线程安全[4]。如图17所示,该方法获取的SynchronizedList的线程安全是通过Synchronized(mutex)修饰代码块来实现的。SynchronizedList.iterator()返回值类型是ArrayList.Iterator(),它是线程不安全的。SynchronizedList.subList的返回值类型也是SynchonizedList,它是线程安全的,SynchronizedList.subList中的锁对象与原SynchronizedList相同,都是原SynchronizedList实例。显然,组合一是线程不安全的,组合二是线程安全的。

    public class Collections {
        public static <T> List<T> synchronizedList(List<T> list) {
            return (list instanceof RandomAccess ?
                    new SynchronizedRandomAccessList<>(list) :
                    new SynchronizedList<>(list));
        }
        
        static class SynchronizedList<E>
            extends SynchronizedCollection<E>
            implements List<E> {
            
            SynchronizedList(List<E> list) {
                super(list);
                this.list = list;
            }
            
            SynchronizedList(List<E> list, Object mutex) {
                super(list, mutex);
                this.list = list;
            }
            
            public void add(int index, E element) {
                //锁对象是当前Collections.SynchronizedList的实例
                synchronized (mutex) {list.add(index, element);}
            }
            public List<E> subList(int fromIndex, int toIndex) {
                synchronized (mutex) {
                    //锁对象为原SynchronizedList的实例,与add()方法相同
                    return new SynchronizedList<>(list.subList(fromIndex, toIndex),
                                                mutex);
                }
            }
        }
        
        static class SynchronizedCollection<E> implements Collection<E>, Serializable {
            final Collection<E> c;  // Backing Collection
            final Object mutex;     // Object on which to synchronize
            
             SynchronizedCollection(Collection<E> c) {
                this.c = Objects.requireNonNull(c);
                mutex = this;
            }
            
            SynchronizedCollection(Collection<E> c, Object mutex) {
                this.c = Objects.requireNonNull(c);
                this.mutex = Objects.requireNonNull(mutex);
            }
            public Iterator<E> iterator() {
                //返回值类型ArrayList.iterator(),它是线程不安全的
                return c.iterator(); // Must be manually synched by user!
            }
        }
    }
    

    图17 Collections中的内部类SynchronizedList和SynchronizedCollection

    3.7.3 CopyOnWriteArrayList

    也可以通过CopyOnWriteArrayList方法来实现线程安全[5]。如图18,在调用add方法时,将原数组copy到新数组,元素的新增在新数组中完成。新数组中新增元素后,在将当前的数组指向新数组。由于元素的新增时,setArray(newElements)的操作是原子性的,其它的修改数组的方法也是类似的(先操作copy的数组,然后通过调用setArray(new Elements)方法),所以get方法不需要再加锁。CopyOnWriteArrayList适用于多读的场景。CopyOnWriteArrayList的iterator获取的COWIterator类不支持remove、add等修改方法,因此COWIterator的其它的查询方法不需要加锁。所以组合一是线程安全的。CopyOnWriteArrayList的subList获取的COWSubList是线程安全的,锁对象是原CopyOnWriteArrayList实例的lock属性,与CopyOnWriteArrayList中方法的锁对象相同,因此组合二是线程安全的。

    public class CopyOnWriteArrayList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
        final transient ReentrantLock lock = new ReentrantLock();
        public boolean add(E e) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len + 1);
                newElements[len] = e;
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
         }
         
         final void setArray(Object[] a) {
            array = a;
         }
         
         //get方法不用加锁
         public E get(int index) {
             return get(getArray(), index);
         }
         
         public List<E> subList(int fromIndex, int toIndex) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                int len = elements.length;
                if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
                    throw new IndexOutOfBoundsException();
                return new COWSubList<E>(this, fromIndex, toIndex);
            } finally {
                lock.unlock();
            }
        }
        
         static final class COWIterator<E> implements ListIterator<E> {
    		//COWIterator.next()方法不用加锁
            @SuppressWarnings("unchecked")
            public E next() {
                if (! hasNext())
                    throw new NoSuchElementException();
                return (E) snapshot[cursor++];
            }
     	    //COWIterator不支持remove()等修改方法
            public void remove() {
                throw new UnsupportedOperationException();
            }
         }
         
          private static class COWSubList<E>
            extends AbstractList<E>
            implements RandomAccess
        {
            private final CopyOnWriteArrayList<E> l;
    
            // only call this holding l's lock
            COWSubList(CopyOnWriteArrayList<E> list,
                       int fromIndex, int toIndex) {
                l = list;
                expectedArray = l.getArray();
                offset = fromIndex;
                size = toIndex - fromIndex;
            }
            public void add(int index, E element) {
                final ReentrantLock lock = l.lock;
                lock.lock();
                try {
                    checkForComodification();
                    if (index < 0 || index > size)
                        throw new IndexOutOfBoundsException();
                    l.add(index+offset, element);
                    expectedArray = l.getArray();
                    size++;
                } finally {
                    lock.unlock();
                }
            }
         }
     }
    

    图18 CopyOnWriteArrayList中的方法及内部类COWIterator和COWSubList

    下表从常用方法get、add等,以及组合方法的维度对比了三种线程安全类。Vector和Collections.synchronizedList的实现大致相同,他们在多读场景下效率低,且组合一是线程不安全的。Vector和Collections.synchronizedList的不同之处包括iterator()方法获取的迭代器是否线程安全等。Vector中的迭代器实现了线程安全,但在方法组合时又线程不安全;且由于每个方法都使用了同步,效率低下,因此Vector已被弃用。相比而言,CopyOnWriteArrayList的读方法不用加锁,在多读场景下效率高,且组合一和组合二都是安全的。如果是多写场景,Collections.synchronizedList的效率更高,但要注意iterator()获取的迭代器中方法的线程安全,以及方法组合等场景下的线程安全。

    表1 Vector、Collections.synchronizedList()、CopyOnWriteArrayList线程安全特性对比

    Vector Collections.synchronizedList() CopyOnWriteArrayList
    get() synchronized修饰(锁对象是this) 锁对象this 不用锁
    add() synchronized修饰 (锁对象是this) 锁对象this 使用l.lock加锁(l为复制数组)
    remove() synchronized修饰(锁对象是this) 锁对象this 使用l.lock加锁(l为复制数组)
    clone() synchronized修饰(锁对象是this) 未实现 浅拷贝(只拷贝list,未拷贝list中的元素),不用锁
    iterator()获取的迭代器类中的方法 方法内使用Vector.this加锁 未加锁,需要额外人工加锁 未加锁,仅支持previous、next等方法,不支持remove、add、set等方法
    sublist() this是锁对象 锁对象this 使用l.lock加锁(l为复制数组)
    方法组合 组合一线程不安全,组合二线程安全 组合一线程不安全,组合二线程安全 组合一、组合二线程安全

    参考资料:

    [1] ArrayList源码中的类注释;

    [2]《阿里巴巴Java开发手册 终极版 v1.3.0》;

    [3] Vector源码;

    [4]Collections.synchronizedList源码;

    [5]CopyOnWriteArrayList源码;

  • 相关阅读:
    tp.c
    trace
    一致性哈希算法
    update_dctcp_alpha
    dctcp-ns2-patch
    C++ inheritance: public, private. protected ZZ
    C++ virtual inheritance ZZ
    C++ 类对象的初始化顺序 ZZ
    C++ inheritance examples
    classifier.cc-recv() [ns2.35]
  • 原文地址:https://www.cnblogs.com/jann8/p/16127203.html
Copyright © 2020-2023  润新知