2013-05-24 12 views
18

हाल ही में मैं एक ट्यूटोरियल पढ़ रहा था, कि मैं एक बयान है कि कहते हैं भर में आया था ..परमाणु संचालन और multithreading

"जावा भाषा विनिर्देश गारंटी देता है कि पढ़ने या एक चर लेखन एक परमाणु ऑपरेशन है (जब तक चर रहा है long या double टाइप करें) long या double के संचालन चर केवल तभी परमाणु हैं जब उन्होंने volatile कीवर्ड के साथ घोषित किया। "

AtomicInteger या AtomicLong कि getAndDecrement(), getAndIncrement() और getAndSet() जो परमाणु कर रहे हैं की तरह तरीकों प्रदान करता है।

मैं उपरोक्त कथन से थोड़ा भ्रमित हो गया .. और आप कृपया स्पष्ट सकता है जबAtomicInteger या AtomicLong वर्गों का उपयोग करने के।

उत्तर

35

a = 28 (aint होने के साथ) एक परमाणु ऑपरेशन है। लेकिन a++ एक परमाणु ऑपरेशन नहीं है क्योंकि इसे एक के मूल्य, एक वृद्धि, और परिणाम के लिए एक लिखने की आवश्यकता है। नतीजतन, यदि आपने थ्रेड-सुरक्षित काउंटर को लागू करने के लिए a++ का उपयोग किया है, तो आप समसामयिक रूप से मूल्य को पढ़ने के दो धागे (उदाहरण के लिए 26) हो सकते हैं, फिर दोनों इसे बढ़ाते हैं और इसे एक साथ लिखते हैं, जिसके परिणामस्वरूप 27 परिणामस्वरूप, परिणामस्वरूप 28.

परमाणु इंटेगर आपके द्वारा सूचीबद्ध किए गए परमाणु संचालन प्रदान करके इस समस्या को हल करता है। मेरे उदाहरण में, आप उदाहरण के लिए incrementAndGet() का उपयोग करेंगे, जो गारंटी देता है कि अंत मूल्य 28 है और 27 नहीं।

+1

फिर हमें 'अस्थिर' का उपयोग क्यों करना होगा, अगर हम "डबल" या "लंबे" प्रकार के चर पर संचालन करते हैं? – MaheshVarma

+6

यदि आप एक AtomicXxx का उपयोग करते हैं, तो आपको अस्थिरता का उपयोग करने की आवश्यकता नहीं है, क्योंकि परमाणु वस्तुएं अस्थिरता से अधिक गारंटी प्रदान करती हैं। एक अस्थिर पूर्णांक पर 'ए ++' करने से ऑपरेशन परमाणु नहीं होता है। यह केवल गारंटी देता है कि एक और धागा बढ़ने के बाद के नए मूल्य को देखेगा। लंबे या दोहरे मूल्यों के लिए नए मान निर्दिष्ट करते समय, यह भी गारंटी देता है कि लेखन एक परमाणु संचालन है (क्योंकि एक गैर-अस्थिर लंबे या दोहरे चर के लिए लिखना 4 बाइट लिखने में होता है, फिर अन्य 4 बाइट लिखते हैं)। सामान्य रूप से अस्थिर चर के ऊपर परमाणु वस्तुओं को पसंद करें। –

+1

'ए = 28' परमाणु होने की गारंटी नहीं है यदि' ए' लंबा या दोहरा है, जब तक कि यह भी अस्थिर न हो। – assylias

6

परमाणु का मतलब है कि ऑपरेशन के बीच कुछ होने की संभावना के बिना पूरा हो जाता है। जैसे। GetAndDecrement(), परमाणु इंटेगर पर, गारंटी देता है कि परिवर्तनीय वापस आ गया है और एक ही समय में कमी आई है।

यदि यह परमाणु संचालन नहीं था, तो मूल्य कम होने के लिए संभावना (उदाहरण के लिए 3 से 2) तक मौजूद होगी, फिर किसी अन्य धागे द्वारा संशोधित (उदाहरण के लिए इसे 2 से 5 में बदलना), फिर वापस लौटाया गया 5.

0

मुझे लगता है कि इसका क्या अर्थ है कि लंबा और डबल-रीड ऑपरेशन परमाणु है और लिखना ऑपरेशन परमाणु है। लेकिन एक पढ़ना + लिखना परमाणु नहीं है।

volatile long num; 
num = num+1 

उपरोक्त धागा सुरक्षित नहीं है। वहां दो अलग-अलग ऑपरेशन पढ़ते हैं और लिखते हैं। उनमें से प्रत्येक परमाणु होने की गारंटी है, लेकिन पूरी अभिव्यक्ति नहीं है।

इसे थ्रेड सुरक्षित बनाने के लिए आपको एटमिकलांग का उपयोग करने और getAndIncrement फ़ंक्शन का उपयोग करने की आवश्यकता होगी।

+0

यह सही विपरीत कहता है: 'लंबे समय में; ए = 1; ', दूसरा कथन परमाणु होने की गारंटी नहीं है। – assylias

+0

नहीं यह नहीं करता है - "लंबे या दो प्रकार के ऑपरेशंस वेरिएबल केवल अस्थिर होते हैं यदि वे अस्थिर कीवर्ड के साथ घोषित होते हैं", अस्थिर – gkamal

+0

पर ध्यान दें आपका पहला वाक्य अस्थिरता के संदर्भ में भ्रामक है। – assylias

0

आप जिन नंबरों से आप काम कर रहे हैं, उनकी सीमा पर ऊपरी/निचली सीमा के आधार पर आप int या long का उपयोग करते हैं। कृपया परमाणु के साथ लंबे समय तक गैर-परमाणु व्यवहार मिश्रण न करें। जो भी आपने ऊपर लिखा है वह सही है लेकिन आप शायद दोनों अवधारणाओं को मिला रहे हैं। परमाणुXXक्स उन मामलों में अधिक उपयोगी हैं जहां आप "& सेट" की तुलना कर रहे हैं। उदाहरण तब भी जब पूर्णांक संशोधित किया जा सकता के लिए/atomically निम्नलिखित कोड को पढ़ने के लिए बहु-क्रम वातावरण में गलत हो जाएगा:

int i =10 
.. 
.. 
.. 
if(i == 10) i++; 

multithread वातावरण में दो धागे इस कोड atomically और मैं का अद्यतन मूल्य और यह लगातार राज्य में आते हैं बनाने पहुँच सकते हैं। ऐसे परिस्थितियों से निपटने के लिए आम तौर पर आप कोड की रक्षा करते हैं "अगर (i == 10) i ++;" सिंक्रनाइज़ ब्लॉक के साथ।हालांकि परमाणु इंटेगर वर्ग धीमी गति से सिंक्रनाइज़ किए गए ब्लॉक का उपयोग किये बिना ऐसी चीजों को प्राप्त करने के लिए एपीआई प्रदान करता है। एटमिक लॉन्ग एपीआई

2

आपको AtomicInteger की आवश्यकता है यदि आपको एक वैरिएबल पढ़ने की आवश्यकता है और को पढ़ने के मूल्य पर परिणाम लिखने की आवश्यकता है। उदाहरण के लिए, i++i (उदा।) पढ़ता है और i+1 लिखता है (उदा। 4)। इस बीच एक धागा बाधित हो सकता है, और तीन अन्य धागे i भी बढ़ते हैं। अब जब हम वापस आते हैं, i वास्तव में मूल्य 6 है लेकिन हमारे धागे अभी भी 4 लिखते हैं, जो पहले इसे पढ़े गए हैं।

AtomicInteger.getAndIncrement सुनिश्चित करता है कि आप बाधित नहीं हैं और इसलिए हमेशा ठीक से बढ़ रहे हैं। इसके अलावा, परिणाम हमेशा स्मृति में फिसल गया है, जबकि एक गैर-अस्थिर i स्मृति में फ़्लश नहीं किया जा सकता है। इस मामले में अन्य धागे परिवर्तन भी नहीं देख सकते हैं।

0

ऑपरेशन की परमाणुता आवश्यक है जब आप एक चर को म्यूट करते हैं। int a = 10; कर एक परमाणु ऑपरेशन है लेकिन यह वह नहीं है जो आपको समस्या देगा। ऑपरेशन देने में समस्या आमतौर पर a++ या a = a + 2; जैसे म्यूटेट कर रही है और इसी तरह।

जावा विशिष्टता गारंटी देता है कि 'पढ़ने' और 'लेखन' परमाणु संचालन उनके संयोजन नहीं हैं। तो एक ऑपरेशन जो 'पढ़ता है, जोड़ता है और फिर परिणाम वापस लिखता है' विनिर्देश के अनुसार परमाणु नहीं है। ऐसे परिचालनों को यौगिक परिचालन कहा जाता है और उन्हें आमतौर पर हमारे कोड में उनके उपयोग के संदर्भ में परमाणु होने की आवश्यकता होती है।

परमाणु प्रकार इस समस्या को हल करने में मदद करते हैं। एक परमाणु प्रकार पर incrementAndget() का उपयोग करके 'पढ़ता है, 1 जोड़ता है और फिर परिणाम को वापस लिखता है और नए परिणाम को पढ़ता है' थ्रेड सुरक्षा के संदर्भ में एक परमाणु ऑपरेशन।

उम्मीद है कि इससे मदद मिलती है। जिस तरह से आपको यह समझा जाना चाहिए (http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/) समवर्ती और धागे की मूल बातें के बारे में लेख। यह खूबसूरती से ऐसी चीजें बताता है।

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