2012-02-20 16 views
12

शीर्षक के रूप में, मैं एक तुलना और स्वैप लागू करने के लिए देख रहा हूँ पता चलता है, लेकिन साथ अधिक से अधिक तुलना:अधिक से अधिक तुलना और स्वैप

if(newValue > oldValue) { 
    oldValue = newValue; 
} 

जहां oldValue कुछ वैश्विक साझा राज्य है क्योंकि मैं एक गैर अवरुद्ध समाधान चाहते हैं

synchronized(locker) { 
    if(newValue > oldValue) { 
     oldValue = newValue; 
    }  
} 

: और newValue प्रत्येक थ्रेड के लिए निजी है, ऐसा किए बिना। अन्य गैर अवरुद्ध आपरेशन के स्रोत कोड का अध्ययन से, मैं (यह मानते हुए मान पूर्णांक हैं) इस के साथ आ गया है:

AtomicInteger oldValue; // shared global variable 

... 

public boolean GreaterThanCAS(int newValue) { 

    while(true) { 
     int local = oldValue; 
     if(local == oldValue) { 
      if(newValue > local) { 
       if(oldValue.compareAndSet(local, newValue) { 
        return true; // swap successful 
       } // else keep looping 
      } else { 
       return false; // swap failed 
      } 
     } // else keep looping 
    } 
} 

जब // else keep looping होता है, इसका मतलब है कि एक और धागा बदल गया है इस बीच में oldValue और इसलिए मुझे लूप करने की ज़रूरत है और पुनः प्रयास करें।

क्या यह कार्यान्वयन सही है (धागा-सुरक्षित)?

+0

यह केवल देखने के लिए जाँच कर रहा है, तो धागा स्विचिंग 'local' चर बताए और देखने के लिए जाँच के बीच हुई अगर वे वही हैं। आपके कथन के बाद थ्रेड स्विचिंग हो सकती है। तो नहीं, यह धागा सुरक्षित नहीं है, लेकिन अवरुद्ध किए बिना मुझे यकीन नहीं है कि आपको कोई समाधान मिलेगा। – Shaded

+0

@ छायांकित: 'oldValue.compareAndSwap (स्थानीय, newValue) 'कॉल भी गलत लौटाता है यदि' oldValue' 'स्थानीय' के बराबर नहीं है, इसलिए यह यहां भी जांचता है। – Tudor

+0

आपको पहले समानता तुलना की आवश्यकता नहीं है। बस "अगर (newValue> स्थानीय) oldValue.CAS (स्थानीय, newValue) और दोहराना" पर्याप्त – BegemoT

उत्तर

7

मुझे आपके कार्यान्वयन के साथ कोई समस्या नहीं दिखाई देती है, बशर्ते कि कोई धागा कभी भी AtomicInteger के मान को कम न करे। यदि वे करते हैं, तो आपका कोड दौड़ की स्थिति के लिए खुला है।

नोट के रूप में इस कोड को सरल बनाया जा सकता है कि: एक से अधिक जांच बेमानी है पहले

while(true) { 
    int local = oldValue.get(); 
    if(newValue > local){ 
     if(oldValue.compareAndSwap(local, newValue) { 
       return true; // swap successful 
     } // else keep looping 
    }else 
     return false; 
} 

तुल्यता की जांच:

public boolean GreaterThanCAS(int newValue) { 
    while(true) { 
     int local = oldValue.get(); 
     if(newValue <= local) { 
      return false; // swap failed 
     } 
     if(oldValue.compareAndSet(local, newValue)) { 
      return true; // swap successful 
     } 
     // keep trying 
    } 
} 
+0

धन्यवाद। आप सही हैं कि कमी से समस्याएं पैदा होंगी, लेकिन मेरे परिदृश्य के लिए, 'oldValue' का मान केवल इस ऑपरेशन को निष्पादित करके बदल सकता है।सरलीकरण सुझाव के लिए भी धन्यवाद। अब जब मैं इसके बारे में सोचता हूं, तो 'अगर' वास्तव में अनावश्यक था। – Tudor

+0

मुझे लगता है कि नाम में 'ग्रेटरथान' के साथ एक विधि में तुलना के लिए '<=' का उपयोग करके आपका कोड थोड़ा अजीब है। –

+0

@ टॉमहॉविन-tackline: मुझे यह संरचना अधिक पठनीय लगता है कि मूल नेस्टेड 'if' कथन। यदि कोई '<= 'पर ऑब्जेक्ट करता है, तो कोई इसे आसानी से' if (! (NewValue> local)) के रूप में आसानी से वाक्यांशित कर सकता है। मैं व्यक्तिगत रूप से इस संदर्भित संस्करण को उत्तर में जो कुछ भी डालता हूं उससे कहीं अधिक स्पष्ट नहीं मिलता है। – NPE

2

मैं इसे लिखने और अधिक की तरह लग रहे करने के लिए फिर से होगा।

अन्यथा इसे ठीक काम करना चाहिए।

10

जावा 8 के बाद से इस updateAndGet के उपयोग के साथ सरल किया जा सकता:

public boolean greaterThanCAS(int newValue) { 
    return oldValue.updateAndGet(x -> x < newValue ? newValue : x) == newValue; 
} 

ध्यान दें कि यह सच भी वापसी होगी मामले में जब पुराने और नए मूल्यों बराबर हैं। यदि यह वांछित व्यवहार नहीं है तो @Adam's answer पर आज़माएं।

+3

'x hengxin

+0

@hengxin, धन्यवाद, तय। – Vadzim

+0

क्या इसके बजाय 'updateAndGet' का उपयोग करना चाहिए? –

2

@ वाडज़िम, मैंने आपकी पोस्ट पर टिप्पणी की होगी, लेकिन स्टैक ओवरफ्लो का कहना है कि मेरे पास टिप्पणियां पोस्ट करने के लिए पर्याप्त अंक नहीं हैं। आपका उत्तर लगभग सही है, लेकिन आपका फ़ंक्शन हमेशा झूठा वापस आ जाएगा क्योंकि getAndUpdate हमेशा आपके मान में पिछले मान, या 'x' देता है। मुझे लगता है कि तुम सब करने की आवश्यकता होगी की जगह है अपने पिछले '==' के साथ '<', जैसे:

// return true if the assignment was made, false otherwise 
public boolean greaterThanCAS(int newValue) { 
    return oldValue.getAndUpdate(x -> x < newValue ? newValue : x) < newValue; 
} 
+0

इंगित करने के लिए धन्यवाद। यह उत्तर भी सही है लेकिन मैंने को 'अपडेट एंड गेट' पर स्विच करने के साथ मेरा तय कर दिया है। ध्यान दें कि पुराने और नए मान बराबर होने पर अब मामले को संभालने में उत्तर अलग-अलग होते हैं। यह संदर्भ पर निर्भर करता है कि कौन सा व्यवहार बेहतर है। – Vadzim

संबंधित मुद्दे