java多线程之同步容器有哪些?

157 阅读2分钟

同步容器即让线程通过互斥的方式来访问的容器,另一种是并发容器(后面文章会介绍)。互斥锁可以通过synchronized或lock来实现,本文接上文详解java多线程之synchronized,以保持内容的连贯性。

java中的同步容器有Vector, Stack, Hashtable, Collections.synchronizedXXX等包装对象,虽然现在已经很少使用,但面试中可能会遇到。

3.4.1 Vector

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    protected Object[] elementData;
    protected int elementCount;
    protected int capacityIncrement;
    
    // 继承自AbstractList
    protected transient int modCount = 0;
}
  • 使用synchronized修饰增删改查方法来同步,同步的是Vector对象

    public synchronized boolean add(E e) {...}
    public boolean remove(Object o) {...}
    public synchronized E set(int index, E element) {...}
    public synchronized E get(int index) {...}
    ...
    
  • 每次修改modCount++, 在迭代,排序...时检查如果modCount变了,抛出ConcurrentModificationException

    @Override
    public synchronized void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int elementCount = this.elementCount;
        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
    
    @Override
    public synchronized void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, elementCount, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
    

3.4.2 Stack

继承自Vector,原理一直,不在赘述

  • 使用synchronized修饰增删改查方法来同步,同步的是Vector对象
  • 每次修改modCount++, 在迭代,排序...时检查如果modCount变了,抛出ConcurrentModificationException

3.4.3 Hashtable

public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {
​
    private transient Entry<?,?>[] table;
    private transient int count;
​
    private int threshold;
    // default to 0.75f
    private float loadFactor;
    private transient int modCount = 0;
  
    private static class Entry<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Entry<K,V> next;
    }
}
  • 使用synchronized修饰增删改查方法来同步,同步的是Vector对象
  • 每次修改modCount++, 在迭代,排序...时检查如果modCount变了,抛出ConcurrentModificationException

3.4.4 Collections.synchronizedXXX

synchronizedCollection.png

包装原list,set,map,通过synchronized(mutex)代码块同步,mutex默认为当前对象.

比如:

static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
​
    final List<E> list;
​
    public void add(int index, E element) {
        synchronized (mutex) {
          list.add(index, element);
        }
    }
}
​
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
    final Collection<E> c;  // Backing Collection
    final Object mutex;
}