인덱스로 요소에 액세스 할 수있는 동시 List 인스턴스를 작성하려면 어떻게해야합니까? JDK에 사용할 수있는 클래스 또는 팩토리 메소드가 있습니까?
List
구체적으로 어떤 원본을 기물 파손으로 간주 되는 요구 사항 이라고 말합니다 . 중재자가 답변이 해체 된 버전의 질문에 답변하지 않는다고 불평하는 사람들로 인해 이미 질문을 잠갔습니다.
인덱스로 요소에 액세스 할 수있는 동시 List 인스턴스를 작성하려면 어떻게해야합니까? JDK에 사용할 수있는 클래스 또는 팩토리 메소드가 있습니까?
List
구체적으로 어떤 원본을 기물 파손으로 간주 되는 요구 사항 이라고 말합니다 . 중재자가 답변이 해체 된 버전의 질문에 답변하지 않는다고 불평하는 사람들로 인해 이미 질문을 잠갔습니다.
답변:
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
}
:
foreach 문이라고합니다) : docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
간단한 호출 동기화 만 있으면 Collections.synchronizedList (List)를 매우 잘 사용할 수 있습니다 .
List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
synchronizedList
는 "동기화"이지만 "동시"는 아닙니다. 인덱스 기반의 많은 List 작업이 그 자체가 원자 적이 지 않으며 더 큰 상호 배제 구성의 일부가되어야한다는 근본적인 문제입니다.
Vector
는 a 보다 더 간단 Collections.synchronizedList(new ArrayList<Object>())
합니다.
위치를 획득하고 주어진 위치에서 요소를 가져 오는 작업은 자연스럽게 약간의 잠금이 필요하기 때문에 (두 목록 사이에 구조적인 변화가있을 수는 없습니다).
동시 수집의 개념은 각 작업 자체가 원자 적이며 명시적인 잠금 / 동기화없이 수행 될 수 있다는 것입니다.
따라서 원자 적 연산 n
으로 주어진 위치 에서 요소를 얻는 것은 List
동시 액세스가 예상되는 상황에서 너무 의미가 없습니다.
다음과 같은 옵션이 있습니다.
Collections.synchronizedList()
: 당신은 어떤 포장 할 수 있습니다 List
구현 ( ArrayList
, LinkedList
또는 제 3 자 목록). 모든 방법 (읽기 및 쓰기)에 대한 액세스는를 사용하여 보호됩니다 synchronized
. iterator()
for 루프를 사용 하거나 향상시킨 경우 수동으로 동기화해야합니다. 반복하는 동안 다른 스레드는 읽지 않아도 완전히 차단됩니다. 각 통화 hasNext
와 next
통화 마다 별도로 동기화 할 수도 있지만 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();
}
}