2016-09-01 1 views
1

아래의 두 예제 클래스에는 기능상의 차이점이 무엇인지 궁금합니다. 어떤 스타일을 다른 스타일보다 선호해야하는지, 왜 선호해야하는지.스레드 안전 클래스를 정의하는 두 가지 방법의 차이점

public class MyQueue { 
    private Queue<Abc> q; 

    public MyQueue() { 
     q = Collections.synchronizedList(new LinkedList<Abc>()); 
    } 

    public void put(Abc obj) { 
     q.add(obj); 
    } 

    public Abc get() { 
     return q.remove(); 
    } 
} 

또는

public class MyQueue { 
    private Queue<Abc> q; 

    public MyQueue() { 
     q = new LinkedList<Abc>(); 
    } 

    public synchronized void put(Abc obj) { 
     q.add(obj); 
    } 

    public synchronized Abc get() { 
     return q.remove(); 
    } 
} 

필자는 - 모두가 수업 시간에이 정도 기능, 개인적인 취향의 문제로까지 완벽하게 정상적으로 작동합니다.

더 많은 차이가 있는지 알려주세요.

+0

단순화 된 경우'synchronizedList()'가'LinkedList' 주위에 래퍼를 추가한다는 것을 제외하고는 약간의 차이가 있습니다. 그래서 모든 호출은 위임되어야합니다. 두 번째 버전에는 메소드 위임의 추가 레이어가 없습니다. – Andreas

답변

2

주요 아키텍처 차이점은 두 번째 구현이 동기화 모니터 (객체 자체)를 외부 세계에 노출한다는 점입니다. 이는 모두가 내부 동기화에 사용하는 것과 동일한 잠금을 획득 할 수 있음을 의미합니다.

MyQueue myQueue = new MyQueue(); // a shared instance 

synchronized(myQueue) { 
    // No one else can call synchronized methods while you're here 
} 

클래스 사용 사례에 따라 이점이 있거나 문제가 발생할 수 있습니다.

첫 번째 구현은 동기화의 세부 사항 (필요한 경우 예를 들어, 당신이 당신의 put()get() 방법으로 일부 동기화되지 않은 코드를 추가 할 수 있습니다) 미래에 새로운 기능을 추가하는 당신에게 조금 더 많은 유연성을 제공 숨어 있다는 사실, 그러나 당신의 명부의 주위에 추가 층이있는의 작은 형벌로 온다.

그렇지 않으면 제시된 기능에 차이가 없습니다.

추 신 : q 선언에 final을 추가하는 것을 잊지 마십시오. 그렇지 않으면 클래스가 안전한 발행물을 보장하지 않으며 완전히 스레드로부터 안전하다고 할 수 없습니다.

+0

잠금을 노출하는 지점이 좋았 기 때문에 기본적으로 내 추가, 제거는 외부 동기화 된 블록과 동기화 될 수 있습니다. 누군가가 그런 방식으로 정렬하려고하는 경우. –

0

목록의 경우 래퍼를 통해 액세스하거나 동기화 된 블록을 사용하여 액세스 할 때마다 기능상 차이가 없어야합니다.

그러나 ConcurrentHashMap의 경우와 같이 래퍼가 제공하는 동기화 메커니즘을 사용하는 것이 더 나은 경우가 있습니다.

예를 들어, 간단한 비 스레드 안전 HashMap에 대한 액세스를 지키려면 모든 읽기/쓰기에 대해 전체 맵 (모든 키)을 잠그면 맵의 동시성에 영향을 미칩니다. ConcurrentHashMap은 맵의 키 세트만을 잠그기 때문에 동시 조작 읽기/쓰기 작업을 위해 성능을 향상시킵니다.

감사합니다.

관련 문제