问:Vector 和 ArrayList、LinkedList 区别? 别离的应用场景?
-
区别
Vector: 底层是数组实现, 线程平安的, 操作的时候应用 synchronized 进行加锁. ArrayList:底层是数组实现, 线程不平安, 查问和批改十分快, 然而减少和删除慢. LinkedList: 底层是双向链表, 线程不平安, 查问和批改速度慢, 然而减少和删除速度快.
-
应用场景
减少和删除场景多则用 LinkedList 查问和批改多则用 ArrayList Vector 曾经很少用了
如果须要保障线程平安,ArrayList 应该怎么做, 用有几种形式?
-
罕用形式是两种, 如果你说你本人写一个 arrayList 保障线程平安, 那就是三种
形式一: 应用 synchronized 加锁 Collections.synchronizedList(new ArrayList<>()); 形式二: 应用 ReentrantLock 加锁 CopyOnWriteArrayList<>()
== 死记硬背必定是不容易记住, 咱们一起浏览一下源码吧 ==
-
synchronizedList 的读写等办法全副都有 synchronized 关键字
// 读写操作都有锁 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);} }
-
CopyOnWriteArrayList 用的是 ReentrantLock 形式加锁
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try {Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally {lock.unlock(); } } public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try {Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else {Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements); } return oldValue; } finally {lock.unlock(); } } // 读操作没有锁 public E get(int index) {return get(getArray(), index); } // 写操作有锁 public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try {Object[] elements = getArray(); E oldValue = get(elements, index); if (oldValue != element) { int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally {lock.unlock(); } }
CopyOnWriteArrayList 和 Collections.synchronizedList 实现线程平安有什么区别?
- 追溯上述的源码 -CopyOnWriteArrayList: 执行批改操作时, 会拷贝一份新的数组进行操作「Arrays.copyOf()」, 空间占用量大, 浪费资源, 代价低廉, 源码外面用 ReentrantLock 可重入锁来保障不会有多个线程同时拷贝一份数组
-
追溯上述的源码 -Collections.synchronizedList: 线程平安的起因是因为它简直在每个办法中都应用了 synchronized 同步锁
CopyOnWriteArrayList 和 Collections.synchronizedList 应用场景
- CopyOnWriteArrayList 场景: 读高性能, 实用读操作远远大于写操作的场景中应用 (读的时候是不须要加锁的, 间接获取, 删除和减少是须要加锁的, 读多写少)
-
synchronizedList: 写操作性能比 CopyOnWriteArrayList 好, 读操作性能并不如 CopyOnWriteArrayList
CopyOnWriteArrayList 的设计思维是怎么的, 有什么毛病?
- 设计思维: 读写拆散 + 最终统一
- 毛病: 通过源码能够晓得, 写操作复制「Arrays.copyOf()」, 内存里会同时驻扎两个对象的内存, 旧的对象和新写入的对象, 内存占用问题突出, 如果对象大则容易产生 Yong GC 和 Full GC