Условия гонки с ссылками на Java - PullRequest
1 голос
/ 19 сентября 2010

Атомное целое число, длинное, логическое значение и т. Д. Используются для выполнения любых атомарных обновлений соответствующих типов, поскольку при выполнении каких-либо манипуляций с ними может возникнуть состояние гонки, например, ++.Но каковы разные случаи со ссылками, где могут быть такие условия гонки?

С наилучшими пожеланиями,
Кешав

Ответы [ 3 ]

2 голосов
/ 19 сентября 2010

Ссылки AFAIK не подчиняются условию гонки, потому что JVM гарантирует, что обновление ссылки является атомарной операцией (в отличие, например, обновление long, когда нижний и верхний 4 байта обновляются в два отдельных этапа).Как отметил SLaks, единственный критический случай - это compareAndSet, который не является атомарным по своей природе.Это очень редко используется с нативными ссылками, но это известная идиома с AtomicReference, когда необходимо обновить две (или более) логически зависимые переменные одновременно. Java Concurrency на практике , раздел 15.3.1 публикует пример для этого, используя AtomicReference для обновления двух переменных (хранящихся в простом классе) в одной элементарной операции.

ОсновнойПричиной существования AtomicReference - кроме согласованности интерфейсов - является видимость и безопасная публикация .В этом смысле атомная переменная является «лучшей volatile».

2 голосов
/ 19 сентября 2010

Операции, подобные ++, зависят от условий гонки, поскольку включают в себя несколько дискретных операций (выборка, приращение, сохранение).

Установка задания (a = b) является отдельной операцией и, следовательно, не зависит от условий гонки.

Операции над ссылочными типами (a.someMethod()) могут делать все, что они хотят, и могут или не могут зависеть от условий гонки.

0 голосов
/ 05 августа 2013

Для целей обучения я написал ConcurrentLinkQueue, используя AtomicReference.

      package concurrent.AtomicE;

      import java.util.concurrent.atomic.AtomicReference;

     public class ConcurrentLinkQueue<V> {
       private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();

   public void fastOffer(final V data){
    final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
    System.out.println(newNode);
    AtomicReference<Node> pointer = firstNodePointer;
    for(;;){
        if(pointer.get() == null){
            if(pointer.compareAndSet(null,newNode)){
                return;
            }
        }
        pointer = pointer.get().getNext();
    }
}

private static class Node<V>{
    private AtomicReference<Node> next = new AtomicReference<Node>();
    private volatile V data = null;
    private String threadName = "";

    Node(V data1,String threadName){
        this.data = data1;
        this.threadName = threadName;
    }

    @Override
    public String toString() {
        return  "threadName=" + threadName +
                ", data=" + data;
    }

    private AtomicReference<Node> getNext() {
        return next;
    }

    private void setNext(AtomicReference<Node> next) {
        this.next = next;
    }

    private V getData() {
        return data;
    }

    private void setData(V data) {
        this.data = data;
    }
}
...