2008-10-02 9 views
9

컬렉션 클래스를 디자인 할 때 스레드를 안전하게하기 위해 개인적으로 잠금을 구현하지 않는 이유가 있습니까? 아니면 컬렉션의 소비자에게 그 책임을 맡겨야합니까?컬렉션을 스레드로부터 안전하게 만드시겠습니까?

+1

컬렉션을 변경하지 못하게하면 모든 것을 잠글 필요가없는 사람이 본질적으로 쓰레드 안전합니다. – Juliet

답변

13

는 스레드로부터 안전하기 위해 개인적으로 잠금 구현되지 않은 이유가 무엇입니까?

이 달려있다. 여러 스레드에서 액세스하는 컬렉션 클래스를 작성하겠습니까? 그렇다면 스레드를 안전하게 만드십시오. 그렇지 않다면 시간을 낭비하지 마십시오. 일이 이런 종류의 사람들이 '조기 최적화'

당신이 가지고있는 문제 해결에 대해 이야기 할 때 참조 할 것입니다. 미래를 볼 수 없기 때문에 앞으로 몇 년 동안 가질 수 있다고 생각하는 미래의 문제를 해결하려고 시도하지 마십시오. 그러면 틀림없이 틀리게 될 것입니다.

참고 : 이 컬렉션에 잠금을 설정하고 추가해야하는 경우 유지 관리가 가능한 방식으로 코드를 작성해야합니다. 내 요점은 수집 스레드 자바의 벡터와 해시 테이블 클래스를 죽인 것입니다 만들기

+2

멀티 쓰레드 성능에 대해 걱정이된다면 몹시 어렵지 않을 것 "이라고 덧붙였다. 순진하기는 쉽지만 잘하기는 쉽지 않다. ConcurrentHashMap의 코드 대 HashMap을 살펴 보자. –

+1

단순한 잠금을 추가하는 것을 언급하고있었습니다. ConcurrentHashMap과 같은 것을 원한다면 분명히 심각한 작업을해야 할 것입니다. –

2

저는 개인적으로 소비자에게 맡깁니다. 컬렉션 클래스를보다 일반적인 것으로 만들 것입니다.

10

자바의 경우 속도를 위해 동기화되지 않은 상태로 두어야합니다. 원하는 경우 컬렉션의 소비자는 synchronization wrapper으로 묶을 수 있습니다.

2

문서에서 스레드가 안전하지 않고 그대로 두거나 응용 프로그램에서 스레드 안전을 원한다면 스레드 안전성을 보장하고 설명서에 해당 스레드를 기록해 두십시오. 유일한 규칙은 그것을 문서화하는 것입니다. 그것 이외에, 당신을위한 수업을 만들고 다른 사람들이 그것을 사용하고 싶다면, 그들은 할 수 있습니다.

0

이렇게하면 터치 한 요소가 다른 사람에 의해 사용되지 않는다는 것을 알고 있더라도 여러 스레드의 컬렉션에 동시에 액세스 할 수 없습니다.

예를 들어 정수 기반 인덱스 접근자를 가진 모음이 될 수 있습니다. 각 쓰레드는 더티 읽기/쓰기에 대한 걱정없이 액세스 할 수있는 인덱스 값을 ID에서 알 수 있습니다.

데이터가 컬렉션에서 읽히고 쓰여지지 않은 경우에만 불필요한 성능 저하가 발생할 수 있습니다.

2

컬렉션 클래스를 찾고 스레드 안전 기능이 필요하고 클래스에 해당 클래스가없는 경우 바로 제공 할 항목을 확인하려면 다음 제안으로 건너 뜁니다. 너의 소장품이 내 관심을 끌지 않을거야.

"처음"에 유의하십시오. 어떤 고객은 그것을 원할 것이고, 어떤 고객은 원하지 않을 것이며, 어떤 고객은 관심을 갖지 않을 것입니다. 소비자를위한 툴킷을 만들려면 두 가지를 모두 제공하지 않는 것이 어떻습니까? 그런 식으로 어느 것을 사용할 지 선택할 수 있지만 thread-safe를 원한다면 여전히주의를 기울여야하며 직접 작성하지 않아도됩니다.

3

컬렉션 클래스는 가능한 한 빨리해야합니다. 따라서 잠금을 해제하십시오.

호출 코드는 잠금 클래스가 컬렉션 클래스와 가장 잘 어울리는 곳을 알 수 있습니다. 최악의 시나리오에서는 앱이 추가 잠금을 추가해야하므로 두 개의 잠금이 발생하여 퍼 퍼트 히트가 두 배가됩니다.

1

스레드를 안전하지 않게하는 주된 이유는 성능입니다. 스레드 안전 코드는 안전하지 않은 코드보다 100 배 느려질 수 있으므로 클라이언트가 기능을 원한다면 상당히 낭비됩니다.

0

소비자에게 맡기는 것이 옳은 방법이라는 데 동의합니다. If는 Collection 인스턴스가 동기화되는지 아니면 다른 객체가 동기화되는지에 대해 훨씬 더 많은 유연성을 제공합니다. 예를 들어 둘 다 업데이트해야하는 두 개의 목록이있는 경우 단일 잠금을 사용하여 단일 동기화 블록에 두 개의 목록을 포함하는 것이 좋습니다.

0

컬렉션 클래스를 만들면 스레드를 안전하게 만들지 마십시오. 올바른 방법 (예 : 정확하고 빠름)을 어렵게 만들고 소비자가 잘못했을 때의 문제 (heisenbugs)를 디버그하기가 어렵습니다.

대신 컬렉션 API 중 하나를 구현하고 Collections.synchronizedCollection (yourCollectionInstance)을 사용하여 필요한 경우 스레드 안전 구현을 얻습니다.

해당 컬렉션을 참조하십시오.귀하의 클래스에서 synchronXXX 메서드 javadoc; 디자인에서 스레드 안전성을 고려했으며 소비자가 스레드 안전 옵션을 사용할 수 있음을 분명히합니다.

1

클래스를 스레드로부터 안전하게 만들려고하면 일반적인 사용 시나리오를 결정해야합니다.

예를 들어 컬렉션의 경우, 모든 속성과 메서드를 개별적으로 스레드로부터 안전하게 만드는 것은 소비자에게 충분하지 않을 수 있습니다. 먼저 개수를 읽은 다음 반복하거나 유사하게 수행하지 않습니다. 카운트가 그것을 읽은 후에 바뀌면 훨씬 좋다.

1

"당신이 필요하지 않으며 사용하지 않는 기능을 구현하지 않는다"입니다. 클라이언트가 클래스 제안에 액세스 할 때마다 동기화 히트를 취하는 것보다 이전에 제안 된 것처럼 스레드 세이프 래퍼에 래핑하거나 메서드의 하위 집합에서 데이터 액세스를 동기화하는 것이 훨씬 쉽습니다. Vector 또는 Hashtable을 사용하는 사람은 거의 없으며, 대체 할 경우 (ArrayList 및 HashMap) 세계가 더 빠르기 때문에 웃을 수 있습니다. 내가 불행한 것은, (C++ 배경에서 나온) "Vector"이름 (STL)을 훨씬 선호하지만, ArrayList가 여기 있습니다. 잠금() 및 잠금 해제() :

1

기본적으로,이 클래스의 방법으로 구현 락킹, 스레드 안전으로 컬렉션을 디자인합니다. 필요한 곳이면 어디든지 전화 할 수 있지만 비워 두십시오. 그런 다음 lock() 및 unlock() 메서드를 구현하는 컬렉션을 서브 클래 싱합니다. 하나의 가격에 두 클래스.

1

컬렉션을 스레드로부터 안전하지 않게하는 정말 좋은 이유는 향상된 단일 스레드 성능을위한 것입니다. 예 : Vector의 ArrayList입니다. 호출자에게 스레드 안전성을 부여하면 동기화되지 않은 유스 케이스가 잠금을 피함으로써 최적화됩니다.

컬렉션을 스레드로부터 안전하게하는 가장 좋은 이유는 향상된 다중 스레드 성능입니다. 예 : HashMap상의 ConcurrentHashMap. CHM은 멀티 스레드 관심사를 내부화하기 때문에 외부 동기화보다 더 효과적으로 동시 액세스를 강화할 수 있습니다.

0

다음은 좋은 시작입니다.

thread-safe-dictionary

그러나 당신은 당신이 컬렉션의 가장 큰 특징 중 하나 잃을 알 - 열거합니다. 열거자를 스레드로부터 보호 할 수는 없습니다. 컬렉션 자체에 대한 인스턴스 잠금을 보유하고있는 고유의 열거자를 구현하지 않으면 열거 할 수 없습니다. 나는 이것이 병목 현상과 잠재적 인 교착 상태를 일으킬 것이라고 생각한다.

6

스레드 안전 컬렉션은 속일 수 있습니다. Jared Par는 스레드 안전 컬렉션에 대한 몇 가지 흥미로운 기사를 올렸습니다.

스레드 안전 컬렉션 수준이 여러 개인 경우가 있습니다. 나는 찾을 대부분의 사람들은 정말 무슨 뜻인지 스레드 안전 수집을 말할 때 "컬렉션을 해당하지 않습니다 수정 및 여러 스레드에서 액세스 할 때 손상 일"

을 ...

하지만를 구축하는 경우 데이터 스레드 안전 목록이 너무 쉽습니다. 왜 프레임 워크에 이러한 표준 모음을 추가하지 않았습니까?

답변 : 디자인으로 인해 코드가 코드로 연결되기 때문에 ThreadSafeList는 실질적으로 사용할 수없는 클래스 입니다.

이 일반적으로 사용되는 방법을 조사 할 때까지이 디자인의 결함은 분명히 이 아닙니다. 예를 들어, 첫 번째 요소를 목록에서 빼내려고 시도하는 코드는 다음과 같습니다.

static int GetFirstOrDefault(ThreadSafeList<int> list) { 
    if (list.Count > 0) { 
     return list[0]; 
    } 
    return 0; } 

이 코드는 고전적인 경쟁 조건이다. 리스트에 하나의> 요소 만있는 경우를 고려하십시오. 다른 스레드가 if 문과 return 문 사이에서 해당 요소를 제거하면 return 문은 목록의 잘못된 인덱스에 액세스하려고하므로 예외가 발생합니다. ThreadSafeList 데이터 스레드 안전이 있지만, 같은 객체

http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx

http://blogs.msdn.com/b/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

0

에 다음 호출에서 하나의 호출의 반환 값의 유효성을 보장 아무것도 경우 JDK 5로 없다 java.util.concurrent의 이미 구현 된 콜렉션 중 하나가 작동하면 처음 볼 스레드 안전 콜렉션이 필요합니다. 의 저자 인 Java Concurrency Practice (대부분의 클래스를 작성한 사람 포함)은 올바르게 수행하는 것이 매우 어렵고 특히 성능이 중요하다고 지적합니다. 큐 외에도,이 패키지 공급 컬렉션 구현은 멀티 스레드 상황에서 사용하기 위해 설계

인용 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html

동시 컬렉션 : ConcurrentHashMap의, ConcurrentSkipListMap과, ConcurrentSkipListSet, 으로 CopyOnWriteArrayList, 및 CopyOnWriteArraySet.많은 스레드 주어진 모음에 액세스 할 것으로 예상되는 경우, ConcurrentHashMap의 동기화 된 의 HashMap에 일반적으로 바람직 이며, ConcurrentSkipListMap과 는 동기 트리 맵에 일반적으로 바람직하다. CopyOnWriteArrayList는 예상 읽기 수와 순회 수가 수보다 많으면 동기화 된 ArrayList가 보다 좋습니다.

관련 문제