我们知道,ArrayList是非线程安全的,如果在线程安全的环境下,我们可以用Vector。

那么,如果我们需要用线程安全、链表结构的List怎么办,LinkedList不是线程安全的。JDK有没有类似Vector的数据结构呢?

如果没有,或者我们找不到这样的类,那么我们可能就得自己去封装LinkedList去实现一个线程安全的链表结构的List了。

本篇文章介绍Collections提供的通用解决方案:Collections.synchornized*

先上一段代码:

    public static void main(String[] args) {
        List<String> threadSafeLinkedList = Collections.synchronizedList(new LinkedList<>());
        threadSafeLinkedList.add("A");
        threadSafeLinkedList.add("B");
        threadSafeLinkedList.add("C");
        System.out.println(threadSafeLinkedList);
    }

使用Collections.synchronizedList封装了原始的LinkedList,将原来非线程安全的列表变成了线程安全的列表,并且不改变内部的数据结构。

Collections.synchronizedList是怎么实现的呢?

    public static <T> List<T> synchronizedList(List<T> list) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
    }

先判断List是否继承了RandomAccess,下面我们看一下SynchronizedList的实现

static class SynchronizedList<E>
        extends SynchronizedCollection<E>
        implements List<E> {
        private static final long serialVersionUID = -7754090372962971524L;

        final List<E> list;

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

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return list.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return list.hashCode();}
        }

        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 E remove(int index) {
            synchronized (mutex) {return list.remove(index);}
        }

        public int indexOf(Object o) {
            synchronized (mutex) {return list.indexOf(o);}
        }
        public int lastIndexOf(Object o) {
            synchronized (mutex) {return list.lastIndexOf(o);}
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            synchronized (mutex) {return list.addAll(index, c);}
        }

        public ListIterator<E> listIterator() {
            return list.listIterator(); // Must be manually synched by user
        }

        public ListIterator<E> listIterator(int index) {
            return list.listIterator(index); // Must be manually synched by user
        }

        public List<E> subList(int fromIndex, int toIndex) {
            synchronized (mutex) {
                return new SynchronizedList<>(list.subList(fromIndex, toIndex),
                                            mutex);
            }
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            synchronized (mutex) {list.replaceAll(operator);}
        }
        @Override
        public void sort(Comparator<? super E> c) {
            synchronized (mutex) {list.sort(c);}
        }

        /**
         * SynchronizedRandomAccessList instances are serialized as
         * SynchronizedList instances to allow them to be deserialized
         * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
         * This method inverts the transformation.  As a beneficial
         * side-effect, it also grafts the RandomAccess marker onto
         * SynchronizedList instances that were serialized in pre-1.4 JREs.
         *
         * Note: Unfortunately, SynchronizedRandomAccessList instances
         * serialized in 1.4.1 and deserialized in 1.4 will become
         * SynchronizedList instances, as this method was missing in 1.4.
         */
        private Object readResolve() {
            return (list instanceof RandomAccess
                    ? new SynchronizedRandomAccessList<>(list)
                    : this);
        }
    }

可以看到原理非常简单,就是在所有访问方法之前,使用synchornized关键字的锁。

类似Collections.synchronizedList的方法很多。
比如,我们需要线程安全的TreeMap,可以使用Collections.synchronizedMap()。

下面列出所有的Collections.synchonized*

public static <T> Collection<T> synchronizedCollection(Collection<T> c);

public static <T> Set<T> synchronizedSet(Set<T> s);

public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s);

public static <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s);

public static <T> List<T> synchronizedList(List<T> list);

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);

public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);

public static <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m);