2015-02-01 4 views
3

2 개의 AtomicReferences에 대해 스왑 메소드를 구현하려고했습니다.2 개의 다른 AtomicReferences에서 2 개의 값을 교환하십시오.

public void swap(AtomicReference<Object> a, AtomicReference<Object> b) { 
    while (true) { 
     Object value1 = a.get(); 
     Object value2 = b.get(); 

     if (a.compareAndSet(value1, value2) && b.compareAndSet(value2, value1)) return; 
    } 
} 

제 생각에는이 해결책이 올바르지 않습니다. 여러 스레드가 동시에이 방법을 사용하는 경우, 다음과 같은 시나리오로 이어질 수 :

T1: ...get(); get(); compareAndSet() == true //-> BREAK (scheduler) 
T2: ...get(); get(); compareAndSet() == true; compareAndSet() == true; return; 

이 의미, T1은 a의 값을 설정했지만 B의 값을 설정하여 실패합니다. T1은 AtomicReference가 설정된 경우 EVEN 프로세스를 반복합니다.

당신 같은 사람이 더 좋은 아이디어를 갖고 있습니까? 이것을 어떻게 구현합니까? 하나의 AtomicReference 만 있으면 쉽게 될 것입니다. 어쩌면 그것은 2 AtomicReference를 사용하는 것이 가능하지 않으며 Object []를 가리키는 AtomicReference를 사용하는 것을 고려해야합니다.

스칼라에서이 방법은 원자 블록을 가지고 있기 때문에 구현하기가 쉽습니다.

class Swappy[A](_a: A, _b: A) { 

    @volatile 
    var a = Ref(_a) 
    @volatile 
    var b = Ref(_b) 

    def swap(): Unit = { 
    atomic { 
     implicit tx => 
      val tmp = a 
      a = b 
      b = tmp 
    } 
    } 

    def elems: (A, A) = (a.single(), b.single()) 
} 
+0

스칼라에 대해 모르겠다.하지만 스칼라가 저레벨 CPU의 원자 명령을 자체적 인 항목으로 래핑하지 않는 한, 솔직히 그것이 어떻게 작동 하는지를 알지 못한다. – doublep

+0

사실 그것은 "실제"저급 원자량이 아닙니다. 그러나 블록의 끝에서 모든 것이 정확하다면 영향을받는 값이 변경되지 않으면 자체 검사를합니다. 그렇지 않다면, 그것은 되돌아 가서 원자 블록의 시작부터 시작합니다. :) – codepleb

+0

가능한 복제본 [Java Atomicity & 좋은 비교 및 ​​스왑 프레임 워크?] (http://stackoverflow.com/questions/14771174/java-atomicity-a-good-compare-and-swap-framework) – rbp

답변

1

나는 다른 접근 방식으로 해결책을 만들었습니다. 이것은 100 % 스레드 안전해야합니다. 하나의 AtomicReference 만 사용하도록 전환했습니다. 누구든지 더 좋은 방법을 찾을 수 있다면 자유롭게 대답을 작성하십시오. :)

package test; 

import java.util.concurrent.atomic.*; 

public class ScalaSTMPendant { 

    AtomicReference<Object[]> a; 

    public ScalaSTMPendant(Object a, Object b) { 
     this.a = new AtomicReference<>(new Object[] {a,b}); 
    } 

    public void swap() { 
     while (true) { 
      Object[] origin = a.get(); 

      Object[] swapped = new Object[] {origin[1], origin[0]}; 

      if (a.compareAndSet(origin, swapped)) return; 
     } 
    } 

    public Object[] elems() { 
     Object[] temp = a.get(); 
     return new Object[] {temp[0], temp[1]}; 
    } 
} 
+0

그것은 가치가있다.'a.get()'을 세 번 호출하지 말라. 'origin'에서'value1'과'value2'를 추출 할 수 있습니다. – doublep

+0

@doublep : 사실, 편집하겠습니다. – codepleb

0

Exchanger은 도움이 되나요? 나는 누가 교환하고 있는지 확실하지 않지만 교환기는 당신이 원자 적으로 스왑을하는 것을 도울 것입니다.

또한 위의 scala 샘플은 ScalaSTM을 사용합니다. 다른 STM 구현 (또는 심지어 ScalaSTM)을 사용하여 Java에서 동일한 작업을 수행 할 수 있습니다. 예 : Multiverse.

관련 문제