[JDK]: CopyOnWriteArrayList, CopyOnWriteArraySet 원본 코드 분석

4632 단어 JDK
CopyOnWriteArrayList 컨테이너는 Collections입니다.synchronizedList(List list)의 대체 방안,Copy OnWrite Array List는 어떤 상황에서는 더 좋은 성능을 가지고 쓰기 장면보다 읽기를 더 많이 고려한다. 만약에 모든 읽기 조작을 잠그면 한 개의 읽기 라인만 잠금을 얻을 수 있기 때문에 다른 읽기 라인은 기다려야 하기 때문에 성능에 큰 영향을 미친다.CopyOnWrite Array List는'쓸 때 복제'용기라고 하는데 다중 루틴이 용기의 대상을 조작할 때 용기를 한 부 복제하는 것이다. 이렇게 하면 루틴 내부의 수정은 다른 루틴과 무관하고 이렇게 설계하면 다른 읽기 루틴을 막지 않는다.JDK에서 1.5 자바를 시작하고 패키지에 CopyOnWrite 메커니즘을 사용하여 이루어진 두 개의 병렬 용기를 제공한다. 이것은CopyOnWriteArrayList와CopyOnWriteArraySet이다.
CopyOnWriteArrayList 소스
먼저 CopyOnWrite Array List 용기의 실현 원리를 말하자면 용기에 대한 조작이 필요할 때 용기를 한 부 복사하고 용기에 대한 수정 등 조작은 모두 용기의 복사에서 한다. 조작이 끝나면 용기의 복사를 원래의 용기로 가리킨다.이런 디자인의 장점은 읽기와 쓰기의 분리를 실현하고 읽기가 막히지 않는다는 것이다.다음 소스는 CopyOnWrite ArrayList의dd 메서드 구현입니다.
public void add(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+
                                                    ", Size: "+len);
            Object[] newElements;
            int numMoved = len - index;
            //1、         
            if (numMoved == 0)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                newElements = new Object[len + 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            //2、           
            newElements[index] = element;
            //3、          
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

위의 세 가지 절차는 쓸 때 복제하는 사상을 실현했고 데이터를 읽을 때list를 잠그지 않는다. 왜냐하면 쓰기 작업은 원래 용기의 복사에서 이루어졌기 때문이다.그리고 용기 복사를 수정하는 과정에서 새로운 읽기 라인이 들어오면 오래된 데이터를 읽을 수 있다는 것을 알 수 있다.읽은 코드는 다음과 같습니다.
public E get(int index) {
        return get(getArray(), index);
    }

final Object[] getArray() {
       return array;
   }

CopyOnWrite 동시 컨테이너는 여러 개의 동시 장면을 읽는 데 사용됩니다.예를 들어 화이트 리스트, 블랙 리스트, 상품 유형의 방문과 업데이트 장면.
CopyOnWriteArrayList의 단점
CopyOnWrite Array List의 실현 원리에서 볼 수 있듯이 용기 대상이 필요할 때 복사하기 때문에 두 가지 문제가 존재한다. 그것이 바로 메모리 점용 문제와 데이터 일치성 문제이다.
메모리 사용량 문제
원래의 대상을 복사해야 하기 때문에 일정한 비용이 필요하다.특히 컨테이너의 개체가 너무 크면 복제본으로 인해 차지하는 메모리가 두 배로 증가합니다. (원래 메모리에 있는 개체는 여전히 사용되고 있고 복사한 후에 두 개의 개체가 메모리에 있기 때문에 메모리가 두 배로 증가합니다.)그리고 높은 병발 장면에서 모든 라인이 하나의 대상을 메모리에 복사하기 때문에 이런 상황은 더욱 뚜렷하게 나타난다.JVM의 최적화 메커니즘으로 인해 빈번한 YoungGC와 FullGC를 터치하여 전체 시스템의 성능을 떨어뜨릴 것이다.
데이터 일관성 문제
CopyOnWriteArrayList는 실시간 일치성을 보장할 수 없습니다. 읽기 루틴은 인용을 원래의 대상을 다시 가리키기 전에 다시 읽은 데이터가 낡기 때문에 CopyOnWriteArrayList는 최종 일치성을 보장할 수 있습니다.따라서 실시간 일치성이 필요한 장면에서는 CopyOnWrite Array List를 사용할 수 없습니다.
CopyOnWriteArrayList 매듭
  • CopyOnWriteArrayList는 읽기와 쓰기가 적은 장면에 적용
  • 용기 대상을 동시에 조작할 때ConcurrentModificationException을 던지지 않으며 되돌아오는 요소는 교체기가 만들 때의 요소와 일치합니다
  • 용기 대상의 복제는 일정한 비용이 필요하다. 만약에 대상이 메모리를 너무 많이 차지하면 빈번한 YoungGC와FullGC
  • 를 초래할 수 있다.
  • CopyOnWriteArrayList는 데이터의 실시간 일치성을 보장할 수 없고 최종 일치성만 보장할 수 있다
  • CopyOnWriteArraySet
    CopyOnWriteArrayList를 바탕으로 이루어진 유일한 차이점은 add에서 호출된 것이 CopyOnWriteArrayList의ddIfAbsent 방법인데 현재 Object 그룹을 두루 훑어보는 것이다. 예를 들어 Object 그룹에 현재 요소가 있으면 바로 되돌아오고 없으면 Object 그룹의 끝에 넣고 되돌아온다.
    참조: 1. CopyOnWriteArrayList 소스 분석

    좋은 웹페이지 즐겨찾기