问: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
发表回复