7

मैं कक्षा द्वारा प्रदान किए गए परमाणु संचालन द्वारा परमाणुता को कैसे प्राप्त किया जाता है यह जानने के लिए java.util.concurrent.atomic.AtomicInteger के स्रोत कोड के माध्यम से जा रहा था। उदाहरण AtomicInteger.getAndIncrement के लिए() विधि स्रोत मैं पाश के लिए एक अनंत अंदर आपरेशन के अनुक्रम लिखने के प्रयोजन को समझने में सक्षम नहीं कर रहा हूँ के रूप मेंjava.util.concurrent.atomic पैकेज में परिभाषित कक्षाओं में परमाणुता कैसे प्राप्त की जाती है?

public final int getAndIncrement() { 
    for (;;) { 
     int current = get(); 
     int next = current + 1; 
     if (compareAndSet(current, next)) 
      return current; 
    } 
} 

इस प्रकार है। क्या यह जावा मेमोरी मॉडल (जेएमएम) में किसी भी विशेष उद्देश्य की सेवा करता है। कृपया मुझे वर्णनात्मक समझ खोजने में मदद करें। अग्रिम में धन्यवाद।

+1

आप अनदेखा कर रहे हैं कि उस लूप में एक विधि कहा जा रहा है और उस विधि का परिणाम लूप को तोड़ने की स्थिति है। Google "तुलना करें और स्वैप करें" –

+1

यह 'गोटो' के लिए क्लासिक उपयोग केस है। एक 'गोटो' भाषा में हम अनंत लूप का उपयोग करते हैं। –

उत्तर

4

मैं लिखने के प्रयोजन को समझने में सक्षम नहीं कर रहा हूँ लूप के लिए अनंत के अंदर संचालन का अनुक्रम।

यह समझने के लिए कि यह एक अनंत लूप में क्यों है, मुझे यह समझने में मदद मिलती है कि compareAndSet क्या करता है और यह कैसे झूठा हो सकता है।

Atomically sets the value to the given updated value if the current 
value == the expected value. 

Parameters: 
    expect - the expected value 
    update - the new value 
Returns: 
    true if successful. False return indicates that the actual value was not 
    equal to the expected value 

तो तुम Returns संदेश पढ़ा और चाहते हैं कि कैसे संभव है?

यदि दो धागे एक ही समय के करीब incrementAndGet का आविष्कार कर रहे हैं, और वे दोनों current == 1 मान डालते हैं और देखते हैं। दोनों धागे एक थ्रेड-स्थानीय next == 2 बनाएंगे और compareAndSet के माध्यम से सेट करने का प्रयास करेंगे। दस्तावेज के अनुसार केवल एक धागा जीत जाएगा और जो धागा खो देता है उसे फिर से प्रयास करना चाहिए।

इस प्रकार सीएएस काम करता है। यदि आप असफल होते हैं तो आप मान को बदलने का प्रयास करते हैं, फिर से प्रयास करें, यदि आप सफल होते हैं तो जारी रखें।

अब बस क्षेत्र को अस्थिर के रूप में घोषित नहीं करेगा क्योंकि वृद्धि परमाणु नहीं है। तो कुछ इस तरह मैं समझाया

volatile int count = 0; 

public int incrementAndGet(){ 
    return ++count; //may return the same number more than once. 
} 
+1

इसे स्पष्ट करने के लिए बहुत बहुत धन्यवाद। –

6

मैं लूप के लिए अनंत के अंदर संचालन के अनुक्रम को लिखने के उद्देश्य को समझने में सक्षम नहीं हूं।

इस कोड का उद्देश्य यह सुनिश्चित करना है कि volatile क्षेत्र एक synchronized लॉक की भूमि के ऊपर के बिना उचित रूप से अद्यतन किया जाता है। जब तक कि इस क्षेत्र को अद्यतन करने के लिए प्रतिस्पर्धा करने वाले बड़ी संख्या में थ्रेड नहीं होते हैं, तो यह संभवतः इसे पूरा करने के लिए बहुत कम समय तक स्पिन करेगा।

volatile कीवर्ड दृश्यता और स्मृति सिंक्रनाइज़ेशन गारंटी प्रदान करता है लेकिन अपने आप में कई संचालन (परीक्षण और सेट) के साथ परमाणु संचालन सुनिश्चित नहीं करता है। यदि आप परीक्षण कर रहे हैं और फिर volatile फ़ील्ड सेट कर रहे हैं तो रेस-स्थितियां हैं यदि एकाधिक थ्रेड एक ही समय में एक ही ऑपरेशन करने की कोशिश कर रहे हैं। इस मामले में, यदि एकाधिक थ्रेड एक ही समय में AtomicInteger को बढ़ाने की कोशिश कर रहे हैं, तो आप वृद्धि में से किसी एक को याद कर सकते हैं। समवर्ती कोड यहाँ स्पिन पाश और compareAndSet अंतर्निहित तरीकों सुनिश्चित करें कि volatile int केवल करने के लिए 4 (उदाहरण के लिए) यदि यह अभी भी करने के लिए 3.

  1. t1 बराबर है परमाणु पूर्णांक और यह हो जाता है अद्यतन किया जाता है बनाने के लिए उपयोग करता है 0.
  2. t2 है परमाणु पूर्णांक हो जाता है और यह 0.
  3. t1 यह 0 है सुनिश्चित करने के लिए atomically परीक्षण यह करने के लिए 1 कहते हैं
  4. t1 है, यह है, और भंडार 1.
  5. टी 2 1 से
  6. जोड़ता है
  7. टी 2 परमाणु यह सुनिश्चित करने के लिए परीक्षण 0 है, यह नहीं है, इसलिए इसे स्पिन करना और पुनः प्रयास करना है।
  8. t2 परमाणु पूर्णांक हो जाता है और यह 1 है यह सुनिश्चित करना है 1.
  9. t2 कहते हैं 1 यह
  10. को t2 atomically परीक्षण, यह है, और भंडार 2.

क्या यह जावा मेमोरी मॉडल (जेएमएम) में किसी भी विशेष उद्देश्य की सेवा करता है।

नहीं, यह वर्ग और विधि परिभाषा के उद्देश्य में कार्य करता है और झामुमो और volatile चारों ओर भाषा परिभाषाओं का उपयोग करती है अपने उद्देश्य को प्राप्त करने।जेएमएम परिभाषित करता है कि synchronized, volatile, और अन्य कीवर्ड और कैश और केंद्रीय मेमोरी के साथ कितने धागे इंटरैक्ट करते हैं। यह ज्यादातर ऑपरेटिंग सिस्टम और हार्डवेयर के साथ देशी कोड इंटरैक्शन के बारे में है और जावा कोड के बारे में कभी भी, शायद ही कभी होता है।

यह compareAndSet(...) तरीका है जिसके Unsafe वर्ग जो कुछ रैपर के साथ ज्यादातर देशी तरीकों में फोन करके झामुमो के करीब हो जाता है है:

public final boolean compareAndSet(int expect, int update) { 
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 
} 
+0

वोल्टाइल की मेरी समझ के अनुसार: यह सिंक्रनाइज़ेशन या किसी भी प्रकार की स्पष्ट लॉकिंग के बिना दृश्यता उद्देश्य हल करता है। इसलिए, पढ़ने/लिखने की निरंतर दृश्यता के लिए अस्थिरता के बिना अस्थिरता का उपयोग किया जा सकता है। तो, सिंक्रनाइज़ेशन के लिए लूप के लिए इस विशेष का उपयोग क्यों करें? यदि आप लूप और सिंक्रनाइज़ेशन के बीच संबंध के बारे में और अधिक समझा सकते हैं, तो यह एक बड़ी मदद होगी। तत्काल उत्तर के लिए धन्यवाद। –

+1

@ वैभववराज - लूप के पास सिंक्रनाइज़ेशन के साथ कुछ लेना देना नहीं है। सीएएस ऑपरेशन सफल होने तक यह loops। –

+2

'अस्थिर' दृश्यता के बारे में है; 'परमाणु इंटेगर' लगभग * लॉक-मुक्त परमाणु * है। आप बिना किसी रिट्री के हासिल कर सकते हैं। अनंत पाश = retries। –

1

जावा के compareAndSet CPU पर तुलना और स्वैप (कैस) निर्देश देखें http://en.wikipedia.org/wiki/Compare-and-swap आधारित है सुरक्षित नहीं परिदृश्य से है। यह किसी दिए गए मान पर स्मृति स्थान की सामग्री की तुलना करता है और केवल तभी, यदि वे समान हैं, तो उस स्मृति स्थान की सामग्री को किसी दिए गए नए मान में संशोधित करता है।

वृद्धि के मामले में और गेट हम वर्तमान मूल्य पढ़ते हैं और compareAndSet(current, current + 1) पर कॉल करते हैं। यदि यह झूठा रिटर्न देता है तो इसका मतलब है कि एक और थ्रेड ने वर्तमान मूल्य को हस्तक्षेप और बदल दिया, जिसका अर्थ है कि हमारा प्रयास विफल हो गया है और इसे पूरा होने तक पूरे चक्र को दोहराने की आवश्यकता है।

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