关于java:arrayList相关面试题

38次阅读

共计 2592 个字符,预计需要花费 7 分钟才能阅读完成。

问: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

正文完
 0