如果多线程并发的访问与一个数据结构,那么很容易破坏一个数据结构。
例如,一个线程可能要向一个散列表中插入一条数据的过程中,被剥夺了控制权。如果另外一个线程也开始遍历同一个链表,很可能造成混乱,抛出异常或者陷入死循环。这就是为什么HashMap不是线程安全的原因。
一、旧的线程安全的集合
通过同步包装器将集合变成线程安全的:
List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>()); Map<K,V> synchMap = Collections.synchronizedList(new HasMap<K,V>());
查看源代码可以发现,就是返回了一个Collections的内部类map,这个map中所有方法都使用同步代码块进行了同步操作:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { return new SynchronizedMap<>(m); }
private static class SynchronizedMap<K,V> implements Map<K,V>, Serializable { private static final long serialVersionUID = 1978198479659022715L; private final Map<K,V> m; // Backing Map final Object mutex; // Object on which to synchronize SynchronizedMap(Map<K,V> m) { this.m = Objects.requireNonNull(m); mutex = this; } SynchronizedMap(Map<K,V> m, Object mutex) { this.m = m; this.mutex = mutex; } public int size() { synchronized (mutex) {return m.size();} } public boolean isEmpty() { synchronized (mutex) {return m.isEmpty();} } public boolean containsKey(Object key) { synchronized (mutex) {return m.containsKey(key);} } public boolean containsValue(Object value) { synchronized (mutex) {return m.containsValue(value);} } public V get(Object key) { synchronized (mutex) {return m.get(key);} } public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} } public V remove(Object key) { synchronized (mutex) {return m.remove(key);} } public void putAll(Map<? extends K, ? extends V> map) { synchronized (mutex) {m.putAll(map);} } public void clear() { synchronized (mutex) {m.clear();} }
//省略........
}