[java] Java JDK에 동시 목록이 있습니까?

인덱스로 요소에 액세스 할 수있는 동시 List 인스턴스를 작성하려면 어떻게해야합니까? JDK에 사용할 수있는 클래스 또는 팩토리 메소드가 있습니까?



답변

java.util.concurrent 에는 동시 목록 구현이 있습니다. 특히 CopyOnWriteArrayList 입니다.


답변

인덱스 기반 액세스에 신경 쓰지 않고 List의 삽입 순서 유지 특성을 원한다면 java.util.concurrent.ConcurrentLinkedQueue를 고려할 수 있습니다. Iterable을 구현하므로 모든 항목을 추가 한 후에는 Enhanced for 구문을 사용하여 컨텐츠를 반복 할 수 있습니다.

Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();

//Multiple threads can safely call globalQueue.add()...

for (String href : globalQueue) {
    //do something with href
}


답변

간단한 호출 동기화 만 있으면 Collections.synchronizedList (List)를 매우 잘 사용할 수 있습니다 .

 List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());


답변

위치를 획득하고 주어진 위치에서 요소를 가져 오는 작업은 자연스럽게 약간의 잠금이 필요하기 때문에 (두 목록 사이에 구조적인 변화가있을 수는 없습니다).

동시 수집의 개념은 각 작업 자체가 원자 적이며 명시적인 잠금 / 동기화없이 수행 될 수 있다는 것입니다.

따라서 원자 적 연산 n으로 주어진 위치 에서 요소를 얻는 것은 List동시 액세스가 예상되는 상황에서 너무 의미가 없습니다.


답변

다음과 같은 옵션이 있습니다.

  • Collections.synchronizedList(): 당신은 어떤 포장 할 수 있습니다 List구현 ( ArrayList, LinkedList또는 제 3 자 목록). 모든 방법 (읽기 및 쓰기)에 대한 액세스는를 사용하여 보호됩니다 synchronized. iterator()for 루프를 사용 하거나 향상시킨 경우 수동으로 동기화해야합니다. 반복하는 동안 다른 스레드는 읽지 않아도 완전히 차단됩니다. 각 통화 hasNextnext통화 마다 별도로 동기화 할 수도 있지만 ConcurrentModificationException가능합니다.

  • CopyOnWriteArrayList: 수정하는 데 비용이 많이 들지만 기다리지 않아도 읽을 수 있습니다. 반복자는 던지지 않으며 ConcurrentModificationException반복하는 동안 다른 스레드가 목록을 수정하더라도 반복자가 생성 될 때 목록의 스냅 샷을 반환합니다. 자주 업데이트되지 않는 목록에 유용합니다. addAll업데이트에는 대량 작업 이 선호됩니다. 내부 어레이는 여러 번 복사되지 않습니다.

  • Vector: 매우 비슷 synchronizedList하지만 반복도 동기화됩니다. 그러나 ConcurrentModificationException반복하는 동안 다른 스레드가 벡터를 수정하면 반복자가을 던질 수 있습니다 .

다른 옵션:

  • Collections.unmodifiableList(): 잠금이없고 스레드 안전하지만 수정할 수 없음
  • Queue또는 Deque목록 끝에 만 추가 / 제거하고 목록을 반복하는 경우 대안이 될 수 있습니다. 인덱스로 액세스 할 수 없으며 임의의 위치에서 추가 / 제거 할 수 없습니다. 그들은 더 나은 성능과 더 나은 동시 액세스로 여러 개의 동시 구현을 가지고 있지만이 질문의 범위를 벗어납니다. JCTools 도 살펴볼 수 있습니다. 여기에는 단일 소비자 또는 단일 생산자에 특화된 더 많은 성능의 큐 구현이 포함되어 있습니다.

답변

여기에 이미지 설명을 입력하십시오

CopyOnWriteArrayList는 기본 배열의 새로운 복사본을 만들어 모든 변이 연산 (추가, 설정 등)이 구현되는 ArrayList의 스레드 안전 변형입니다.

CopyOnWriteArrayList는 동기화 된 List가 List 인터페이스와 java.util.concurrent 패키지의 일부 및 스레드 안전 콜렉션을 구현하는 동시 대안입니다.

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

CopyOnWriteArrayList는 페일 세이프이며 반복하는 동안 기본 CopyOnWriteArrayList가 수정 될 때 별도의 ArrayList 사본을 사용하는 경우 ConcurrentModificationException을 발생시키지 않습니다.

복사 배열은 복제 된 복사본이 생성 될 때마다 모든 업데이트 작업을 수행하기 때문에 비용이 많이 듭니다. CopyOnWriteArrayList는 잦은 읽기 작업에만 최선의 선택입니다.

/**
         * Returns a shallow copy of this list.  (The elements themselves
         * are not copied.)
         *
         * @return a clone of this list
         */
        public Object clone() {
            try {
                @SuppressWarnings("unchecked")
                CopyOnWriteArrayList<E> clone =
                    (CopyOnWriteArrayList<E>) super.clone();
                clone.resetLock();
                return clone;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }

답변