Условия расы с Java ссылки
-
04-10-2019 - |
Вопрос
Атомное целое число, длительное, логическое и т. Д. Используется для выполнения любых атомных обновлений к соответствующим типам, поскольку может быть состояние гонки, когда мы выполняем любые манипулирования на них, например, ++. Но каковы разные случаи со ссылками, где могут быть такие условия расы?
С уважением,
Кешав
Решение
Ссылки AFAIK не подвержены состоянии гонки, потому что JVM гарантирует, что эталонное обновление является атомной операцией (в отличие от, например, обновление long
, где нижние и верхние 4 байта обновляются в двух разных шагах). Единственный критический случай, как отметил Слакс, compareAndSet
который не атомной природой. Это очень редко используется с родными ссылками, но это известная идиома с AtomicReference
Когда необходимо обновить два (или более) логически кодовых переменных одновременно. Java параллелизм на практике, раздел 15.3.1 публикует пример для этого, используя AtomicReference
Чтобы обновить две переменные (хранится в простом классе) в одной атомной работе.
Основная причина существования AtomicReference
- Помимо консистенции интерфейсов - это видимость а также Безопасная публикация. Отказ В этом смысле атомная переменная является «лучше volatile
".
Другие советы
Операции типа ++
подлежат гоночным условиям, потому что они включают в себя несколько незаметных операций (приема, приращение, магазин).
Установка ссылки (a = b
) - это единственная операция и, таким образом, не подвержена гоночным условиям.
Операции по ссылочным типам (a.someMethod()
) может сделать все, что они хотят и могут или не могут подвергаться воздействию расходов.
Для изучения цели я написал ConculrentLinkQueue, используя 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;
}
}