ظروف السباق مع مراجع Java
-
04-10-2019 - |
سؤال
يتم استخدام عدد صحيح الذرية ، الطويل ، المنطقي وما إلى ذلك للقيام بأي تحديثات ذرية للأنواع المعنية حيث قد يكون هناك حالة سباق عندما ننفذ أي معالجة عليها ، على سبيل المثال. ولكن ما هي الحالات المختلفة مع المراجع التي قد تكون هناك مثل هذه الظروف العرق؟
تحياتي الحارة،
كيشاف
المحلول
لا تخضع مراجع AFAIK لحالة السباق لأن JVM يضمن أن التحديث المرجعي هو عملية ذرية (على عكس تحديث أ long
, ، حيث يتم تحديث البايتات السفلية والأعلى في خطوتين متميزتين). الحالة الحرجة الوحيدة ، كما لاحظت Slaks ، هي compareAndSet
وهو ليس ذري بطبيعته. نادرًا ما يتم استخدامه مع المراجع الأصلية ، لكنه تعبير معروف مع AtomicReference
عندما تكون هناك حاجة إلى تحديث اثنين (أو أكثر) متغيرات معتمدة منطقيا في وقت واحد. تزامن جافا في الممارسة, ، القسم 15.3.1 ينشر مثالًا على ذلك ، باستخدام AtomicReference
لتحديث متغيرين (مخزّن في فئة بسيطة) في عملية ذرية واحدة.
السبب الرئيسي لوجود AtomicReference
- بصرف النظر عن اتساق الواجهات - هو الرؤية و منشور آمن. بهذا المعنى ، فإن المتغير الذري هو "أفضل volatile
".
نصائح أخرى
عمليات مثل ++
تخضع لظروف السباق لأنها تنطوي على عمليات سرية متعددة (الجلب ، الزيادة ، المتجر).
تحديد مرجع (a = b
) هي عملية واحدة وبالتالي لا تخضع لظروف السباق.
العمليات على الأنواع المرجعية (a.someMethod()
) يمكنهم فعل أي شيء يريدونه وقد يخضع أو لا يخضع لظروف السباق.
لغرض التعلم ، كتبت 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;
}
}