2015-02-01 3 views
3

Я попытался реализовать метод swap для 2 AtomicReferences.Swap 2 значения в 2 разных AtomicReferences

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 но потерпит неудачу, установив значение Ь. T1 будет повторять процесс EVEN, если установлен AtomicReference a.

У кого-то из вас есть лучшая идея, как реализовать что-то подобное? Было бы легко, если бы у вас был только один AtomicReference. Возможно, это невозможно, используя 2 AtomicReference, и я должен рассмотреть возможность использования одного AtomicReference, который указывает на Object [].

В Scala этот метод очень прост в реализации, поскольку у вас есть атомные блоки.

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

Не знаю Scala, но я, откровенно говоря, не вижу, как это может работать в принципе, если Scala не обманывает атомарные команды низкоуровневого процессора в свои собственные вещи. – doublep

+0

На самом деле это не «настоящий» низкоуровневый атомный материал. Но он проверяет себя в конце блока, если все по-прежнему корректно (измененные значения не изменяются). Если нет, он откатится и начнет с начала атомного блока. :) – codepleb

+0

Возможный дубликат [Java Atomicity & good Compare и Swap framework?] (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()' три раза. Вы можете просто извлечь 'value1' и' value2' из 'origin'. – doublep

+0

@doublep: Верно, я его отредактирую. – codepleb

0

Помогла ли вам помощь Exchanger? Я не уверен, кто что-то меняет, но обменник поможет вам обменять атомарно.

Кроме того, пример scala выше использует ScalaSTM. Вы можете сделать то же самое в Java, используя другую реализацию STM (или даже ScalaSTM). Например: Multiverse.

Смежные вопросы