0

풀 메커니즘을 개발 중입니다. 풀의 객체는 다른 스레드에 의해 사용됩니다. 따라서 이러한 객체의 비 최종 속성에 액세스 할 때 happens-before 관계가 있음을 보장해야합니다.원자력이 아닌`happen-before` 관계를 보장하기 만하면, 동시 클래스 나 동기화 된 블록을 사용해야합니까?

한 번에 하나의 스레드 만 지정된 객체에 액세스하므로 아무런 원자 성도 보장 할 필요가 없습니다. happens-before 만 달성해야 할 때 더 최적화 된 것은 무엇입니까? 최종 속성에 대해 동기화 된 블록을 사용하려면 최종 속성 중 하나를 읽거나 수정할 때마다? 또는 ConcurrentMap과 같은 동시 클래스를 사용 하시겠습니까?

는 (I 분명히 자성을 제공 할 필요가 풀 자체의 속성이 질문을하고 있지 않다, 나는 단지 풀에서 얻은 개체의 특성에 대한이 질문에 요구하고) 당신이 필요 아니라 경우

+0

개체가 불변 일 경우 더 쉬울 것입니다 ... – assylias

+0

이것은 풀을위한 개체이므로 다시 사용할 수 있습니다. 이 경우 불변 개체에 의존하기가 어렵습니다. – FBB

답변

3

최종 속성에 대한 동기화 된 블록을 읽을 때마다 또는 최종 속성 중 하나를 수정 하시겠습니까? 또는 ConcurrentMap과 같은 동시 클래스 인 을 사용 하시겠습니까?

동기화고유 잠금 또는 잠금 장치를 모니터로 알려진 내부 개체 주위에 내장되어 있습니다. 모든 객체에는 고유 한 잠금이 있습니다. 관습 적으로, 객체의 필드에 대해 배타적이고 일관된 액세스가 필요한 스레드는 객체의 고유 한 잠금을 액세스하기 전에 가져와야하며, 잠금이 끝나면 내장 잠금을 해제해야합니다.

ConcurrentMap 즉의 구현 ConcurrentHashMap재진입 잠금 상호 배타적 로크 인에게 사용은 잠금 unlock() 메소드를 호출 할 때까지 lock() 방법에 의해 취득 스레드에 의해 유지된다.비록, ReentrantLocksynchronized keyword에 인수 암시 잠금으로 보장 동일한 가시성과 순서 부를 제공, 그것은 더 많은 기능을 제공하고 특정 측면에서 다릅니다 긴 대기에 잠금 장치를 제공하는 fairness property를 지정하여

  1. ReentrantLock 공정 할 수 스레드, 경합의 경우.
  2. 은 다른 스레드가 사용 가능하거나 보유하지 않은 경우에만 잠금을 획득하는 편리한 방법을 제공하여 잠금 대기중인 스레드의 차단을 줄입니다. 특정 시간 동안 잠금을 사용할 수없는 경우 시간 초과가있는 tryLock()을 사용하여 시간 초과 할 수 있습니다.
  3. synchronized keyword의 경우 스레드는 제한된 시간 동안 잠금 대기를 차단할 수 있으며이를 제어 할 방법이 없습니다. ReentrantLock은 잠금을 기다리는 동안 스레드를 인터럽트하는 데 사용할 수있는 lockInterruptibly()이라는 메서드를 제공합니다.

    boolean replace(K key, int hash, V oldValue, V newValue) { 
           // called by replace(K key, V oldValue, V newValue) 
         lock(); // acquire the lock 
         try { 
          HashEntry<K,V> e = getFirst(hash); 
          while (e != null && (e.hash != hash || !key.equals(e.key))) 
           e = e.next; 
    
          boolean replaced = false; 
          if (e != null && oldValue.equals(e.value)) { 
           replaced = true; 
           e.value = newValue; 
          } 
          return replaced; 
         } finally { 
          unlock(); // unlock 
         } 
        } 
    

    재진입 동기화를 사용 등 put(), writeObject(java.io.ObjectOutputStream) 같이 또한 구현되는 다른 기능이있다 :

사용 reentrant lock의 예 ConcurrentHashMap의 내측 replace(K key, V oldValue, V newValue) 기능 implementaion에서 도시 될 수있다ReentrantLock을 사용하면 동기화 코드가 스레드를 차단하지 못하도록 많은 추가 예방 조치를 취해야합니다. 그래서 나는 귀하의 케이스에 대해 ConcurentMap이 바람직하다고 생각합니다.

참조 :

  1. Intrinsic Locks and Synchronization
  2. ReentrantLock Class
  3. Difference between synchronized vs ReentrantLock
  4. ConcurrentHashMap
+0

실제로 synchronized 키워드는 재진입 동기화도 제공합니다. http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html. 그러나 상세한 답변을 주셔서 감사합니다. 다른 유효한 포인트를 제공해주십시오. – FBB

+0

예, 가능하지만 ReentrantLock 클래스가 이미 제공하는 많은 컨트롤을 가져와야합니다. ReentrantLock 클래스가 우리에게 제공하는 이점을 지적하고자했습니다. 나는 다시 한 번 신중하게 내 글을 읽었으며 ** 재진입 동기화 ** 직후 마지막 파라에서 ReentrantLock 클래스를 언급 했어야했다. 답변을 업데이트했습니다. 감사합니다 :) – Sage

+0

참고로, @ewernli 대답도 참조하십시오. 누가 내 사용 사례에 대한 답변을 제공합니까? – FBB

-1

을 일어난 일을 보장하기 전에, 나는 당신이 잠그고 자하는 Object를 가지고있는 Synchronized 블록을 만들 수 있다고 생각합니다, 그리고 나서이 블록에서이 객체를 사용하기 전에 당신이 원하는 것을하고 나서 Object로부터 물건을 호출 한 다음 예를 들어

을 해제

public void doSomething(){ 
    synchronized(myObject){ 
     doAnotherThing(); 
     myObject.doStuff(); 
    } 
} 

나는 그 전에 ConcurrentMap을 시도하지 않았다 ... 그리고 그런데, 내가 생각하기에 당신이 맞다고 생각하기 때문에 당신의 예제를 명확히 해주세요 !!

+0

downvoters에 대한 이유를 설명하십시오 ... 감사합니다 –

+1

나는 당신을 downvote하지 않았지만, 당신이 질문에 대답하지 않기 때문에 그것이라고 생각합니다. 'synchronized' 키워드를 사용하는 방법을 설명하면서,이 키워드를 사용하는 장점/불편 함과'java.util.concurrent' 패키지의 클래스를 비교해달라고 요청했습니다. – FBB

+0

설명해 주셔서 고맙습니다. 지금은 알겠습니다. 유감스럽게 생각합니다. –

0

발생 가능 관계가 on이어야하는 필드가 프리미티브이고 Java 5 이상을 사용하는 경우 Java 5+에서 일어난 일이 사전에 확인되도록 volatile 키워드를 사용할 수 있습니다.

개체 인 경우 synchronized 키워드 또는 순진한 동기화보다 성능이 좋은 java.util.concurrent 패키지의 클래스를 사용하여 동기화를 사용해야합니다. 예를 들어, ConcurrentHashMap은 보통 각 빈마다 별도의 잠금을 사용하므로 잠금 경합이 적기 때문에 Collections.synchronizedMap(Map)보다 성능이 좋습니다.

+0

'java.util.concurrent'의 클래스에 대한 잠금 경합이 적지 만 그 메소드는 원 자성을 보장해야하므로 동의하지 않습니다. 종료? – FBB

+1

CHM은 개체에 대한 변경 내용이 표시되지 않을 것이라고 보증하지 않습니다 (예 : 두 번의 호출 사이에 발생하지 않음). – assylias

+0

@assylias : 예, http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html – FBB

2

주어진 오브젝트에 액세스 할 수있는 바와 같이 한 번에 하나의 스레드 만 사용하면 어떤 원자도 보장 할 필요가 없습니다.

내가 알맞게 말하면 개체가 스레드간에 공유되지만 실제로는 여러 스레드에서 동시에 액세스하지 않는 동시성이 없습니다. 어떤 동기화가 필요한지 궁금합니다.

저는 wondering the same이었습니다. 결론은 객체 Y가 객체 X에 대한 액세스를 동기화하면 객체 X는 동기화 될 필요가 없습니다. 풀의 경우 동기화 된 메서드를 사용하여 개체를 얻거나 해제하여 풀의 개체를 보호 할 수 있습니다.

풀의 객체 O를 생각해 봅시다. 풀에는 동기화 된 두 가지 방법 Object acquire()release(Object o)이 있습니다. 객체 O를 스레드 T1에서 T2로 전달하려면 T1이 먼저 O를 릴리스해야하며 T2는 O를 획득해야합니다.T1의 릴리스와 T2의 획득 사이에는 이미 우연한 관계가 있기 때문에 객체 O 자체는 동기화 될 필요가 없습니다.

+0

와우, 네 말이 맞아. 나는 그걸 몰랐어. 그러나 귀하의 질문에 대한 링크에서 누군가는 미래 코드 변경에 대해 경고하고, 나는 그에 동의하는 경향이 있습니다. 나는 대답을 upvote하지만 그것을 받아들이지 않는다. 왜냐하면 @Sage가 내가 알고 있다고 생각하지 않고 실제 질문에 대답하기 때문이다. 미안하다 : p – FBB

+0

@Djebel 당신이 ' 필요가 없다. 풀이 올바르게 구현되면 풀의 개체를 동기화 할 필요가 없으며 나중에 필요하지 않게됩니다. 동기화보다 "최적화 된"접근 방식은 없습니다. :) – ewernli

+0

예, @ assylias의 의견은 내 유스 케이스에 대한 의문을 불러 일으켰지 만 한 번에 하나의 스레드 만 객체 O에 액세스 할 수있는 한 당신 말이 맞습니다. , 그리고 쓰레드 간의 교환은 동기화되고, happen-before가 보장된다. – FBB