1.CopyOnWriterArrayList是强一致性列表吗?
不是
CopyOnWriteArrayList
不提供强一致性主要是因为它的修改操作是在一个新的拷贝上进行的,而不是直接在原始数据结构上。这种设计决策带来了一些影响:
- 读取操作不阻塞:
CopyOnWriteArrayList
的读取操作是在原始数组上进行的,无锁,而写入在原数组的拷贝上进行。因此,写入操作期间,读取操作不会被阻塞,允许并发读取。但这也意味着在写入操作完成之前,读取操作可能会看到旧的数据。- 写入操作的延迟: 当有写入操作发生时,
CopyOnWriteArrayList
会创建一个新的数组,并在上面执行修改。在这个过程中,其他线程可能仍然在引用旧的数组。因此,在写入操作完成之前,其他线程可能无法感知到最新的修改。下面是简化的
CopyOnWriteArrayList
的部分关键代码,以便更好地理解:public class CopyOnWriteArrayList<E> { private transient volatile Object[] array; // ... /** *写入操作 / public boolean add(E element) { synchronized (this) { Object[] currentArray = array; //1.拷贝原数组 Object[] newArray = Arrays.copyOf(currentArray, currentArray.length + 1); //2.在新副本上执行添加操作 newArray[currentArray.length] = element; //3.将原数组引用指向新副本 array = newArray; return true; } } // ... public E get(int index) { return (E) array[index]; } // ... }
在
add
方法中,修改是在一个新的数组上进行的。而get
方法只是直接访问当前数组,没有加锁,因此可能在写入操作进行时看到旧的数组。这就是导致不强一致性的主要原因之一。
2.HashMap允许key为null吗?
允许
key为null时,key的hash值恒为0,元素将被存储在数组的第一个位置
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } static final int hash(Object key) { int h; //key为null,hash恒为0 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } final V putVal(int hash, K key, V value,<