2011-01-03 5 views
4

Collection을 동기화 상상 :동기화 된 컬렉션을 복제하는 방법은 무엇입니까?

이 컬렉션을 복제 할 수있는 가장 좋은 방법 무엇
Set s = Collections.synchronizedSet(new HashSet()) 

?

원본 복제본에서 복제를 필요로하지 않지만 복제 된 복제본을 반복 할 때 원본 복제본을 동기화 할 필요가없는 것이 좋습니다.

+0

복사 조건은 무엇입니까? 원본 세트가 복사되는 동안 변경 될 수 있습니까? 클론에 의해 무엇을 성취하려고합니까? (귀하의 목표를 달성하는보다 효율적인 방법을 제안 할 수는 있지만 올바른지 확인하기 위해이 질문에 대한 답변이 필요합니다.) –

+0

@Berin Loritsch : 예, 복사 중에 원본 세트가 변경 될 수 있습니다. 나는 데이터 및 동기화의 의미에서 원래 컬렉션에서 독립적이어야 Set에서 Iterator를 얻으려고합니다. – MRalwasser

답변

6

를 사용하여 동기화 된 블록 내부의 복사 생성자 : 당신은뿐만 아니라 동기화 할 사본을해야하는 경우

synchronized (s) { 
    Set newSet = new HashSet(s); //preferably use generics 
} 

, 다시 Collections.synchronizedSet(..)을 사용합니다.

Peter의 의견에 따르면 - 원본 세트의 동기화 된 블록에서이 작업을 수행해야합니다. synchronizedSet의 문서는 이것에 대해 명시 적입니다 :

당신이 노출 방지 다음을 수행하여 설정을 동기화 피할 수 위에

+3

불행히도 이것은 보닛에서 Iterator를 사용하므로이를 안전하게 동기화하기 위해 동기화해야합니다. –

+0

@Peter 그렇습니다. 반복자를 사용하지 않고 컬렉션에 액세스하는 방법은 거의 없습니다. –

+1

이야기의 나쁜면은 메서드 구현 방법을 알아야한다는 것입니다. – Bozho

1

이 반복되는 경우 사용자가 수동으로 돌려 세트에 동기를 잡을 필요가 있습니다 원래의 반복자. 당신이 볼 수 있듯이 Collections.SynchronizedCollection

public Object[] toArray() { 
    synchronized(mutex) {return c.toArray();} 
} 

에서

Set newSet = new HashSet(Arrays.asList(s.toArray())); 

편집은 잠금이 작업이 수행되는 전체 시간 동안 개최됩니다. 따라서 안전한 데이터 복사본이 만들어집니다. Iterator가 내부적으로 사용되는지는 중요하지 않습니다. 돌려 주어진 배열은 로컬 thread만이 참조 가능하기 때문에 thread로부터 안전한 방법으로 사용할 수 있습니다.

참고 : 이러한 문제를 피하려면 2004 년 Java 5.0에 추가 된 동시성 라이브러리의 Set를 사용하는 것이 좋습니다. 제네릭을 사용하면 컬렉션을 더 안전하게 사용할 수 있으므로 제네릭을 사용하는 것이 좋습니다.

+0

여전히 iterator를 사용합니다. – Bozho

+0

사실이지만 복사본을 반복합니다. 이것은 스레드로부터 안전합니다. toArray()는 원자 적이기 때문에 스레드로부터 안전합니다. –

+0

"toArray()"가 원자 적이라고 보장 할 수있는 곳은 어디에도 없습니다. 적어도이 경우 중요합니다. 내가 볼 수있는 유일한 보증은'toArray()'를 호출하면 콜렉션이 배열에 의해 뒷받침 되더라도 배열의 새로운 복사본을 생성한다는 것입니다. 나는 그 가정에 관한 제 코드를 이해하기를 원하지 않을 것입니다. 특히 소스가 노드에 의해 뒷받침되는 경우 (모든 세트 및 LinkedLists의 경우처럼) 배열을 복사하는 데 시간이 걸립니다. 이 경우에는 반복기가 필요합니다. –

3

동기화 된 세트를 사용할 때 세트의 모든 요소에 액세스하는 동기화 오버 헤드가 발생한다는 것을 이해하십시오. Collections.synchronizedSet()은 모든 메서드를 강제로 동기화하는 셸로 집합을 래핑합니다. 아마도 당신이 의도 한 바가 아닐 것입니다. ConcurrentSkipListSet은 여러 스레드가 세트에 쓰는 다중 스레드 환경에서 더 나은 성능을 제공합니다.

ConcurrentSkipListSet하면 다음을 수행 할 수 있습니다 :

Set newSet = s.clone();//preferably use generics 

그것은 스냅 샷 처리를 위해 세트의 복제를 사용하는 것이 드문 일이 아니에요. 그게 네가하는 일이면, 항목이 이미 처리 된 경우를 처리하기 위해 약간의 코드를 추가 할 수 있습니다. 둘 이상의 사본 세트에 포함 된 임시 객체와 관련된 오버 헤드는 일반적으로 Collections.concurrentSet()을 사용하는 일관된 오버 헤드보다 적습니다.

편집 : ConcurrentSkipListSet이 Cloneable이고 스레드 세이프가있는 clone() 메서드를 제공하는 것으로 나타났습니다. Collections.concurrentSet()에 대한 확장 성 및 성능을 잃는 대신에 이것이 최선의 선택이라고 생각하기 때문에 답을 변경했습니다.

관련 문제