IT story

Java의 다른 유형의 스레드 안전 세트

hot-time 2020. 7. 9. 07:58
반응형

Java의 다른 유형의 스레드 안전 세트


Java에서 스레드 안전 세트를 생성하는 다양한 구현 및 방법이있는 것 같습니다. 일부 예는 다음과 같습니다.

1) CopyOnWriteArraySet

2) Collections.synchronizedSet (세트 세트)

3) 동시 스킵리스트 세트

4) Collections.newSetFromMap (새 ConcurrentHashMap ())

5) (4)와 유사한 방식으로 생성 된 기타 세트

이 예제는 동시성 패턴 : Java 6의 동시 세트 구현에서 제공됩니다.

누군가이 예와 다른 점의 차이점, 장점 및 단점을 간단히 설명해 주시겠습니까? Java Std Docs의 모든 것을 이해하고 똑바로 유지하는 데 문제가 있습니다.


1) 이것은 CopyOnWriteArraySet매우 간단한 구현입니다. 기본적으로 배열에 요소 목록이 있으며 목록을 변경할 때 배열을 복사합니다. 이 시점에서 실행되는 반복 및 기타 액세스는 이전 배열을 계속 사용하여 판독기와 기록기 간의 동기화가 필요하지 않습니다 (쓰기 자체를 동기화해야 함). 일반적으로 빠른 설정 작업 (특히 contains())은 배열이 선형 시간으로 검색되므로 매우 느립니다.

자주 읽고 (반복) 자주 변경하지 않는 아주 작은 세트에만 이것을 사용하십시오. (Swings 리스너 세트는 예일 수 있지만 실제로는 세트가 아니며 EDT에서만 사용해야합니다.)

2) Collections.synchronizedSet단순히 원래 세트의 각 방법 주위에 동기화 된 블록을 감 쌉니다. 원본 세트에 직접 액세스해서는 안됩니다. 이것은 세트의 두 가지 메소드를 동시에 실행할 수 없음을 의미합니다 (하나는 다른 쪽이 끝날 때까지 차단됨)-스레드 안전하지만 여러 스레드가 실제로 세트를 사용하는 경우 동시성이 없습니다. 반복자를 사용하는 경우 반복자 호출 사이의 세트를 수정할 때 ConcurrentModificationExceptions을 피하기 위해 일반적으로 외부에서 동기화해야합니다. 성능은 원래 세트의 성능과 비슷합니다 (그러나 일부 동기화 오버 헤드 및 동시에 사용되는 경우 차단).

동시성이 낮고 모든 변경 사항이 다른 스레드에 즉시 표시되도록하려면이 옵션을 사용하십시오.

3) O (log n)에서 가장 기본적인 작업을 수행 ConcurrentSkipListSet하는 동시 SortedSet구현입니다. 반복자가 추가 된 후 제거 및 읽기 / 반복을 수행 할 수 있습니다. 여기서 반복자는 반복자가 작성된 이후 변경 사항에 대해 알려주거나 그렇지 않을 수 있습니다. 대량 작업은 단순히 여러 번의 단일 호출이며 원자 적으로는 아닙니다. 다른 스레드는 그 중 일부만 관찰 할 수 있습니다.

분명히 요소에 대한 전체 순서가있는 경우에만 사용할 수 있습니다. 이것은 O (log n) 때문에 너무 크지 않은 세트에 대해 동시성이 높은 상황에 이상적인 후보처럼 보입니다.

4) ConcurrentHashMap(및 그로부터 파생 된 세트)의 경우 : 여기에서 가장 기본적인 옵션은 hashCode()O (1)에서 ( 평균적으로 좋고 빠르면 평균 이지만 HashMap /과 같이 O (n)으로 저하 될 수 있습니다) 해시 세트. 쓰기에 대한 동시성은 제한적이며 (테이블이 분할되고 필요한 액세스에서 쓰기 액세스가 동기화 됨) 읽기 액세스는 자체와 쓰기 스레드에 완전히 동시 적이지만 현재 변경 내용의 결과를 아직 보지 못할 수 있습니다. 쓴). 반복자는 생성 된 이후 변경 사항을 보거나 보지 못할 수 있으며 대량 작업은 원자 적이 지 않습니다. 크기 조정이 느리기 때문에 (HashMap / HashSet의 경우) 생성시 필요한 크기를 추정하여 3/3이 가득 찼을 때 크기를 조정할 때 크기의 1/3 이상을 사용하여이를 피하십시오.

큰 세트, 양호하고 빠른 해시 함수가 있고 맵을 작성하기 전에 세트 크기 및 필요한 동시성을 추정 할 수있는 경우이를 사용하십시오.

5) 여기서 사용할 수있는 다른 동시지도 구현이 있습니까?


각 수정에 대해 전체 세트를 사용 하고 교체 하여 동시성 관련 특성과 contains()성능 을 결합 할 수 있습니다 .HashSetCopyOnWriteArraySetAtomicReference<Set>

구현 스케치 :

public abstract class CopyOnWriteSet<E> implements Set<E> {

    private final AtomicReference<Set<E>> ref;

    protected CopyOnWriteSet( Collection<? extends E> c ) {
        ref = new AtomicReference<Set<E>>( new HashSet<E>( c ) );
    }

    @Override
    public boolean contains( Object o ) {
        return ref.get().contains( o );
    }

    @Override
    public boolean add( E e ) {
        while ( true ) {
            Set<E> current = ref.get();
            if ( current.contains( e ) ) {
                return false;
            }
            Set<E> modified = new HashSet<E>( current );
            modified.add( e );
            if ( ref.compareAndSet( current, modified ) ) {
                return true;
            }
        }
    }

    @Override
    public boolean remove( Object o ) {
        while ( true ) {
            Set<E> current = ref.get();
            if ( !current.contains( o ) ) {
                return false;
            }
            Set<E> modified = new HashSet<E>( current );
            modified.remove( o );
            if ( ref.compareAndSet( current, modified ) ) {
                return true;
            }
        }
    }

}

Javadocs가 도움이되지 않으면 데이터 구조에 대해 읽을 책이나 기사를 찾아야합니다. 한 눈에보기 :

  • CopyOnWriteArraySet은 컬렉션을 변경할 때마다 기본 배열의 새 복사본을 생성하므로 쓰기 속도가 느리고 반복자가 빠르고 일관됩니다.
  • Collections.synchronizedSet() uses old-school synchronized method calls to make a Set threadsafe. This would be a low-performing version.
  • ConcurrentSkipListSet offers performant writes with inconsistent batch operations (addAll, removeAll, etc.) and Iterators.
  • Collections.newSetFromMap(new ConcurrentHashMap()) has the semantics of ConcurrentHashMap, which I believe isn't necessarily optimized for reads or writes, but like ConcurrentSkipListSet, has inconsistent batch operations.

Concurrent set of weak references

Another twist is a thread-safe set of weak references.

Such a set is handy for tracking subscribers in a pub-sub scenario. When a subscriber is going out of scope in other places, and therefore headed towards becoming a candidate for garbage-collection, the subscriber need not be bothered with gracefully unsubscribing. The weak reference allows the subscriber to complete its transition to being a candidate for garbage-collection. When the garbage is eventually collected, the entry in the set is removed.

While no such set is directly provided with the bundled classes, you can create one with a few calls.

First we start with making a Set of weak references by leveraging the WeakHashMap class. This is shown in the class documentation for Collections.newSetFromMap.

Set< YourClassGoesHere > weakHashSet = 
    Collections
    .newSetFromMap(
        new WeakHashMap< YourClassGoesHere , Boolean >()
    )
;

The Value of the map, Boolean, is irrelevant here as the Key of the map makes up our Set.

In a scenario such as pub-sub, we need thread-safety if the subscribers and publishers are operating on separate threads (quite likely the case).

Go one step further by wrapping as a synchronized set to make this set thread-safe. Feed into a call to Collections.synchronizedSet.

this.subscribers =
        Collections.synchronizedSet(
                Collections.newSetFromMap(
                        new WeakHashMap <>()  // Parameterized types `< YourClassGoesHere , Boolean >` are inferred, no need to specify.
                )
        );

Now we can add and remove subscribers from our resulting Set. And any “disappearing” subscribers will eventually be automatically removed after garbage-collection executes. When this execution happens depends on your JVM’s garbage-collector implementation, and depends on the runtime situation at the moment. For discussion and example of when and how the underlying WeakHashMap clears the expired entries, see this Question, *Is WeakHashMap ever-growing, or does it clear out the garbage keys? *.

참고URL : https://stackoverflow.com/questions/6720396/different-types-of-thread-safe-sets-in-java

반응형