Java의 JDK에 동시 목록이 있습니까?
인덱스로 요소에 액세스할 수 있는 동시 목록 인스턴스를 만들려면 어떻게 해야 합니까?JDK에 사용할 수 있는 클래스 또는 공장 메서드가 있습니까?
ConcurrentLinkedQueue
인덱스 기반 액세스에 관심이 없고 목록의 삽입 순서 보존 특성만 원하는 경우 를 고려할 수 있습니다. Itable을 구현하기 때문에 모든 항목을 추가한 후 확장 구문 기능을 사용하여 내용을 루프할 수 있습니다.
Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();
//Multiple threads can safely call globalQueue.add()...
for (String href : globalQueue) {
//do something with href
}
java.util.concurrent에는 동시 목록 구현이 있습니다.특히 CopyOnWriteArrayList.
면책사항 : 이 답변은 2011년 JDK 5 이전 및 고도의 최적의 동시 API 이전에 발표되었습니다.따라서 다음과 같은 방법이 사용 가능하지만 최선의 방법은 아닙니다.
컬렉션을 매우 잘 사용할 수 있습니다.synchronized List(목록)는 단순한 호출 동기만 필요한 경우 다음과 같습니다.
List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
위치를 획득하고 주어진 위치에서 요소를 가져오는 작업은 당연히 약간의 잠금이 필요하기 때문입니다(목록에 두 작업 간의 구조 변경은 있을 수 없습니다).
동시 수집의 개념은 각 작업이 원자적이며 명시적인 잠금/동기화 없이 수행될 수 있다는 것입니다.
따라서 위치에서 따라서요소를 제자리에 배치한다는 요소를 얻는 것입니다.n
주어진 주어진 곳에서에서List
으로서 원자는 운전을 동시 접근 예상된 상황에서 너무 쉽게 이해하지 않는다.동시 접속이 예상되는 상황에서는 원자적인 조작은 그다지 의미가 없기 때문입니다.
다음과 같은 옵션이 있습니다.
Collections.synchronizedList()
모든 것을 랩할::착용할 수 있것List
구현(실장(ArrayList
,,LinkedList
아니면3rd-party 목록).또는서드파티 리스트 cm이다.모든 메서드(읽기와 쓰기)에 접근하는액세스는 다음 방법으로 보호됩니다 대한모든 방법(읽기 및 쓰기)에를 사용하여 보호될 것이다.synchronized
. 언제 사용하기 ·사용시iterator()
아니면 루프를 향상시켜 수동으로 전체를 반복 동기화되어야 합니다.또는 루프의 경우 확장 기능을 사용하여 반복 전체를 수동으로 동기화해야 합니다.반면 클레임, 다른 스레든다고 읽는 것으로부터 차단됩니다.반복하는 동안 다른 스레드는 읽기조차 완전히 차단됩니다.별도로 각 또, 각각에 대해서 개별적으로 동기화할 수도 있습니다에 동기화할 수 있다.hasNext
★★★★★★★★★★★★★★★★★」next
단, '콜'이 됩니다.ConcurrentModificationException
능합니니다다: 수정하는 것은 비싸지만 읽는 것은 무료입니다
CopyOnWriteArrayList
.반복자는 던지지 않는다.ConcurrentModificationException
반복하는 동안 다른 스레드에 의해 목록이 수정된 경우에도 반복 작성 시 목록의 스냅샷을 반환합니다.자주 업데이트되지 않는 목록에 유용합니다.ations 음음ations음 등의 벌크 조작addAll
을 사용하다이치노Vector
.synchronizedList(new ArrayList<>())
는 던질 수 .ConcurrentModificationException
반복하는 동안 다른 스레드에 의해 벡터가 수정된 경우.
기타 옵션:
Queue
★★★★★★★★★★★★★★★★★」Deque
목록 끝에만 추가/삭제하거나 반복하는 경우 대체 방법이 될 수 있습니다.Queue
는 한쪽 할 수 .Deque
그럼 양단에서 추가 및 삭제를 할 수 있습니다.색인별 액세스 권한이 없습니다. 구현보다 여러 .List
제공할 수 있습니다.Queue javadoc의 "All Known Implementing Classes" (모든 기존 구현 클래스)를 참조하십시오.java.util.concurrent
패키지는 동시입니다.JCTool에 대해서도 살펴볼 수 있습니다.JCTool에는 싱글 컨슈머 또는 싱글 생산자에 특화된 고속 큐 구현이 포함되어 있습니다.Collections.unmodifiableList()
단할 수 없음: " " " , " " " " " 。List.of
& : Java 9 이후로는 수정할 수 없는 목록입니다.
CopyOnWriteArrayList는 모든 변환 조작(추가, 세트 등)이 기본 어레이의 새로운 복사본을 만들어 구현되는 ArrayList의 스레드 세이프 변형입니다.
CopyOnWriteArrayList는 동기화된 목록 구현 목록 인터페이스와 java.util.concurrent 패키지의 일부를 동시에 대체하는 것으로 스레드 세이프 컬렉션입니다.
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Copy On Write Array List는 페일 세이프이며 Concurrent Modification을 발생시키지 않습니다.반복 중에 기본 CopyOnWriteArrayList가 변경되는 예외는 ArrayList의 개별 복사본을 사용하십시오.
일반적으로 복사 배열은 복제된 복사본이 생성되는 모든 업데이트 작업에 포함되기 때문에 비용이 너무 많이 듭니다.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();
}
}
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/CopyOnWriteArrayList.html
https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
- https://www.logicbig.com/tutorials/core-java-tutorial/java-collections/concurrent-collection-cheatsheet.html
요소 에 있는 모든 ), 를 사용할 수 .ConcurrentSkipListMap<Integer, T>
대신해서ArrayList<T>
,예.
NavigableMap<Integer, T> map = new ConcurrentSkipListMap<>();
이렇게 하면 다음과 같이 "목록" 끝에 항목을 추가할 수 있습니다. 작성자 스레드가 하나만 있는 경우(그렇지 않은 경우 사이에 경합 조건이 있습니다).map.size()
그리고.map.put()
):
// Add item to end of the "list":
map.put(map.size(), item);
또, 「리스트」(즉, 맵)내의 임의의 아이템의 값도, 간단하게 변경할 수 있습니다.map.put(index, item)
.
의 평균 )이며, O(log(n))이다.ConcurrentSkipListMap
해제되어 있기 에, 「잠금 없음」이라고 하는 보다 훨씬 .Vector
)ArrayList
를 참조해 주세요.
'하면 '목록'을 반복할 수 요.NavigableMap
인터페이스입니다.
을 모두 '하다'라고 하는 할 수 .List
조건의하고 있는 한할 수 경우), 되고 있지 않은 는, 「」( 「Writer Methods」)에 할 필요가 .remove
방 there 한 모든 하기 위해 플레이트가 시도가 있습니다.필요한 모든 방법을 구현하기 위해 상당히 많은 보일러 플레이트가 필요하지만, 여기 구현을 위한 간단한 시도가 있습니다.
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentSkipListMap;
public class ConcurrentAddOnlyList<V> implements List<V> {
private NavigableMap<Integer, V> map = new ConcurrentSkipListMap<>();
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean contains(Object o) {
return map.values().contains(o);
}
@Override
public Iterator<V> iterator() {
return map.values().iterator();
}
@Override
public Object[] toArray() {
return map.values().toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return map.values().toArray(a);
}
@Override
public V get(int index) {
return map.get(index);
}
@Override
public boolean containsAll(Collection<?> c) {
return map.values().containsAll(c);
}
@Override
public int indexOf(Object o) {
for (Entry<Integer, V> ent : map.entrySet()) {
if (Objects.equals(ent.getValue(), o)) {
return ent.getKey();
}
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
for (Entry<Integer, V> ent : map.descendingMap().entrySet()) {
if (Objects.equals(ent.getValue(), o)) {
return ent.getKey();
}
}
return -1;
}
@Override
public ListIterator<V> listIterator(int index) {
return new ListIterator<V>() {
private int currIdx = 0;
@Override
public boolean hasNext() {
return currIdx < map.size();
}
@Override
public V next() {
if (currIdx >= map.size()) {
throw new IllegalArgumentException(
"next() called at end of list");
}
return map.get(currIdx++);
}
@Override
public boolean hasPrevious() {
return currIdx > 0;
}
@Override
public V previous() {
if (currIdx <= 0) {
throw new IllegalArgumentException(
"previous() called at beginning of list");
}
return map.get(--currIdx);
}
@Override
public int nextIndex() {
return currIdx + 1;
}
@Override
public int previousIndex() {
return currIdx - 1;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void set(V e) {
// Might change size of map if currIdx == map.size(),
// so need to synchronize
synchronized (map) {
map.put(currIdx, e);
}
}
@Override
public void add(V e) {
synchronized (map) {
// Insertion is not supported except at end of list
if (currIdx < map.size()) {
throw new UnsupportedOperationException();
}
map.put(currIdx++, e);
}
}
};
}
@Override
public ListIterator<V> listIterator() {
return listIterator(0);
}
@Override
public List<V> subList(int fromIndex, int toIndex) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean add(V e) {
synchronized (map) {
map.put(map.size(), e);
return true;
}
}
@Override
public boolean addAll(Collection<? extends V> c) {
synchronized (map) {
for (V val : c) {
add(val);
}
return true;
}
}
@Override
public V set(int index, V element) {
synchronized (map) {
if (index < 0 || index > map.size()) {
throw new IllegalArgumentException("Index out of range");
}
return map.put(index, element);
}
}
@Override
public void clear() {
synchronized (map) {
map.clear();
}
}
@Override
public synchronized void add(int index, V element) {
synchronized (map) {
if (index < map.size()) {
// Insertion is not supported except at end of list
throw new UnsupportedOperationException();
} else if (index < 0 || index > map.size()) {
throw new IllegalArgumentException("Index out of range");
}
// index == map.size()
add(element);
}
}
@Override
public synchronized boolean addAll(
int index, Collection<? extends V> c) {
synchronized (map) {
if (index < map.size()) {
// Insertion is not supported except at end of list
throw new UnsupportedOperationException();
} else if (index < 0 || index > map.size()) {
throw new IllegalArgumentException("Index out of range");
}
// index == map.size()
for (V val : c) {
add(val);
}
return true;
}
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public V remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
}
위와 같이 라이터 스레드가 동기화되어 있어도 라이터 스레드가 리스트의 끝에 추가되는 동안 리더 스레드에서 목록을 반복하려고 할 경우 아이템을 드롭할 수 있는 레이스 상태에 빠지지 않도록 주의해야 한다는 점을 잊지 마십시오.
이 경우에도 사용할 수 있습니다.ConcurrentSkipListMap
(같은 레이스 조건의 경고가 여기에 적용됩니다.즉, 라이터 스레드는 1개만 있어야 합니다.)
// Add item after last item in the "list":
map.put(map.isEmpty() ? 0 : map.lastKey() + 1, item);
// Add item before first item in the "list":
map.put(map.isEmpty() ? 0 : map.firstKey() - 1, item);
대부분의 경우 동시 목록이 모델 개체 내에 있거나(어플리케이션 모델 그래프에서 노드를 나타내기 위해 목록과 같은 추상 데이터 유형을 사용하지 않아야 함) 특정 서비스의 일부인 경우 액세스를 직접 동기화할 수 있습니다.
class MyClass {
List<MyType> myConcurrentList = new ArrayList<>();
void myMethod() {
synchronzied(myConcurrentList) {
doSomethingWithList;
}
}
}
종종 이 자극이 되기에 충분하다.만약 당신이 반복하는 데 필요한 그 목록의 사본은 목록이 아닌 자체만 그 동안 반복하기 여러분은 목록이 아닌 복사 부분 동기화에 반복하다.
또한 목록 작업을 동시에 수행할 때는 보통 추가 또는 삭제 또는 복사 이상의 작업을 수행합니다. 즉, 작업이 자체 메서드를 경고하기에 충분할 정도로 의미가 있으며 목록은 스레드 세이프 동작으로 이 특정 목록을 나타내는 특수 클래스의 멤버가 됩니다.
리스트의 동시 실장 및 Vector / Collections에 동의해도 상관없습니다.synchronize List(리스트)는 compare And Add 또는 compare And Remove or get(..., ifAbsentDo)와 같은 것이 확실히 필요한 경우에는 이 트릭을 실행하지 않습니다.Concurrent List 실장 개발자는 동시 목록(및 맵)을 사용할 때 실제 트랜잭션이 무엇인지 고려하지 않고 버그를 도입하는 경우가 많습니다.
트랜잭션이 너무 작아서 동시 ADT(추상 데이터 유형)와의 상호 작용의 의도된 목적을 충족할 수 없는 경우 항상 특수 클래스에서 목록을 숨기고 메서드레벨에서 동기화된를 사용하여 이 클래스 오브젝트 메서드에 대한 액세스를 동기화합니다.그것이 거래가 올바른지 확인할 수 있는 유일한 방법입니다.
다른 방법으로는 할 수 없는 버그를 많이 보았습니다.적어도 코드가 중요하고 돈이나 보안과 같은 것을 다루거나 서비스 품질 측정(메시지를 적어도 한 번만 보내는 등)을 보증하는 경우입니다.
언급URL : https://stackoverflow.com/questions/6916385/is-there-a-concurrent-list-in-javas-jdk
'programing' 카테고리의 다른 글
String.valueOf()와오브젝트.toString() (0) | 2022.08.07 |
---|---|
C의 구조체 및 포인터에 대한 malloc (0) | 2022.08.07 |
v-for 루프에서 li 요소 하나가 클릭된 경우 VueJs가 활성 클래스를 설정함 (0) | 2022.08.07 |
C: 시스템 명령어를 실행하여 출력을 얻으시겠습니까? (0) | 2022.08.07 |
VueJS2에서 이벤트 대상을 $emit 인수로 전달하려면 어떻게 해야 합니까? (0) | 2022.08.07 |