线程安全的方式是建立了list的包装类

 public static <T> List<T> synchronizedList(List<T> list) {
    return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<T>(list) :
                new SynchronizedList<T>(list));//根据不同的list类型最终实现不同的包装类。
    }

其中,SynchronizedList对部分操作加上了synchronized关键字以保证线程安全。但其iterator()操作还不是线程安全的。部分SynchronizedList的代码如下:

public E get(int index) {
        synchronized(mutex) {return list.get(index);}
        }
    public E set(int index, E element) {
        synchronized(mutex) {return list.set(index, element);}
        }
    public void add(int index, E element) {
        synchronized(mutex) {list.add(index, element);}
        }
    public ListIterator<E> listIterator() {
        return list.listIterator(); 
        // Must be manually synched by user 需要用户保证同步,否则仍然可能抛出ConcurrentModificationException
        }

    public ListIterator<E> listIterator(int index) {
        return list.listIterator(index); // Must be manually synched by user <span style="font-family: Arial, Helvetica, sans-serif;">需要用户保证同步,否则仍然可能抛出ConcurrentModificationException</span>
        }

遍历

遍历需要加到synchronized中

返回由指定列表支持的同步(线程安全)列表。为了保证串行访问,对后备列表 的所有 访问都必须通过返回的列表完成,这一点至关重要。
用户在迭代返回的列表时必须手动同步它:
   List list = Collections.synchronizedList(new ArrayList());
       ...
   synchronized (list) {
       Iterator i = list.iterator(); // Must be in synchronized block
       while (i.hasNext())
           foo(i.next());
   }

不遵循此建议可能会导致不确定的行为。
如果指定的列表是可序列化的,则返回的列表将是可序列化的。
形参:
list – 要“包装”在同步列表中的列表。
返回值:
指定列表的同步视图。

特性

  • 读取 写入时线程安全
  • 但是读取性能不如CopyOnWriteArrayList强.
  • 遍历时不同步,所以遍历时的线程不安全.

💡Collections.synchronizedList则可以用在CopyOnWriteArrayList不适用,但是有需要同步列表的地方, 读写操作都比较均匀的地方。