एटॉमिक बुलियन क्या करता है कि एक अस्थिर बूलियन प्राप्त नहीं कर सकता है?
एटॉमिक बुलियन क्या करता है कि एक अस्थिर बूलियन प्राप्त नहीं कर सकता है?
जवाबों:
वे बिलकुल अलग हैं। volatile
पूर्णांक के इस उदाहरण पर विचार करें :
volatile int i = 0;
void incIBy5() {
i += 5;
}
यदि दो थ्रेड्स फ़ंक्शन को समवर्ती रूप से कहते हैं i
, तो बाद में 5 हो सकते हैं, क्योंकि संकलित कोड कुछ इसी तरह होगा (इसके अलावा आप सिंक्रनाइज़ नहीं कर सकते हैं int
):
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
यदि एक चर अस्थिर है, तो इसके लिए प्रत्येक परमाणु पहुंच सिंक्रनाइज़ है, लेकिन यह हमेशा स्पष्ट नहीं होता है कि वास्तव में परमाणु पहुंच के रूप में क्या योग्य है। एक Atomic*
वस्तु के साथ , यह गारंटी है कि प्रत्येक विधि "परमाणु" है।
इस प्रकार, यदि आप का उपयोग एक AtomicInteger
और getAndAdd(int delta)
, आप यह सुनिश्चित करें कि परिणाम होगा हो सकता है 10
। उसी तरह, यदि दो थ्रेड्स एक boolean
चर को समवर्ती रूप से नकारते हैं, तो AtomicBoolean
आप यह सुनिश्चित कर सकते हैं कि इसका मूल मान बाद में है, ए के साथ volatile boolean
, आप नहीं कर सकते।
इसलिए जब भी आपके पास एक फ़ील्ड को संशोधित करने वाले एक से अधिक थ्रेड होते हैं , तो आपको इसे परमाणु बनाने या स्पष्ट सिंक्रनाइज़ेशन का उपयोग करने की आवश्यकता होती है।
का उद्देश्य volatile
एक अलग है। इस उदाहरण पर विचार करें
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
यदि आपके पास एक थ्रेड रनिंग loop()
और दूसरा थ्रेड कॉलिंग है stop()
, तो आप एक लूप में भाग सकते हैं यदि आप छोड़ते हैं volatile
, क्योंकि पहला थ्रेड स्टॉप के मूल्य को कैश कर सकता है। यहाँ, volatile
संकलक के साथ थोड़ा और अधिक सावधान रहने के लिए संकलक को संकेत के रूप में कार्य करता है।
volatile
। सवाल volatile boolean
बनाम के बारे में है AtomicBoolean
।
volatile boolean
पर्याप्त है। यदि कई लेखक भी हैं, तो आपको आवश्यकता हो सकती है AtomicBoolean
।
जब क्षेत्र कहा जाता है तो मैं अस्थिर क्षेत्रों का उपयोग करता हूं, केवल उसके मालिक धागे द्वारा अद्यतन किया जाता है और मूल्य केवल अन्य थ्रेड्स द्वारा पढ़ा जाता है, आप इसे एक प्रकाशन / सदस्यता परिदृश्य के रूप में सोच सकते हैं जहां कई पर्यवेक्षक हैं लेकिन केवल एक प्रकाशक हैं। हालाँकि अगर उन पर्यवेक्षकों को क्षेत्र के मूल्य के आधार पर कुछ तर्क करना चाहिए और फिर एक नए मूल्य को वापस लाना चाहिए तो मैं परमाणु * संस्करण या ताले या सिंक्रनाइज़ किए गए ब्लॉक के साथ जाता हूं, जो भी मुझे सबसे अच्छा लगता है। कई समवर्ती परिदृश्यों में यह मूल्य प्राप्त करने के लिए उबलता है, किसी अन्य के साथ तुलना करें और यदि आवश्यक हो तो अपडेट करें, इसलिए तुलनात्मक और परमाणु * कक्षाओं में मौजूदएंडसेट तरीकों की तुलना करें।
परमाणु वर्गों की एक सूची के लिए java.util.concurrent.atomic पैकेज के JavaDocs की जाँच करें और वे कैसे काम करते हैं (सिर्फ यह सीखा कि वे लॉक-फ्री हैं, इसलिए उन्हें ताले या सिंक्रनाइज़ किए गए ब्लॉक पर एक फायदा है) का एक उत्कृष्ट विवरण है
boolean
var को संशोधित करता है , तो हमें चुनना चाहिए volatile boolean
।
आप ऐसा नहीं कर सकते compareAndSet
, getAndSet
अस्थिर बूलियन साथ परमाणु आपरेशन के रूप में (बेशक जब तक आप इसे सिंक्रनाइज़)।
AtomicBoolean
ऐसी विधियाँ हैं जो अपने यौगिक कार्यों को परमाणु रूप से करती हैं और बिना किसी synchronized
ब्लॉक का उपयोग किए । दूसरी ओर, volatile boolean
केवल कंपाउंड ऑपरेशन कर सकते हैं यदि ऐसा किसी synchronized
ब्लॉक के भीतर किया जाए ।
पढ़ने / लिखने के स्मृति प्रभाव क्रमशः और विधियों के volatile boolean
समान हैं।get
set
AtomicBoolean
उदाहरण के लिए compareAndSet
विधि निम्नलिखित रूप से (बिना किसी synchronized
खंड के) प्रदर्शन करेगी :
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
इसलिए, compareAndSet
विधि आपको एक बार कोड लिखने की गारंटी देगी जो कि केवल एक बार निष्पादित करने की गारंटी है, यहां तक कि कई थ्रेड्स से भी कॉल किया जाता है। उदाहरण के लिए:
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
केवल एक बार श्रोता को सूचित करने की गारंटी है (कोई अन्य धागा सेट होने के बाद फिर से AtomicBoolean
वापस false
सेट करता है true
)।
volatile
कीवर्ड की गारंटी होती है-उस चर को साझा करने वाले थ्रेड्स के बीच संबंध होने से पहले। यह आपको गारंटी नहीं देता है कि उस बूलियन चर का उपयोग करते समय 2 या अधिक धागे एक दूसरे को बाधित नहीं करेंगे।
Atomic*
वर्ग एक volatile
क्षेत्र को लपेटता है ।
वाष्पशील बूलियन बनाम एटॉमिक बुलियन
परमाणु * वर्ग एक ही प्रकार के एक अस्थिर आदिम को लपेटते हैं। स्रोत से:
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void set(long newValue) {
value = newValue;
}
इसलिए यदि आप सब कर रहे हैं और एक परमाणु स्थापित कर रहे हैं * तो आप के बजाय बस एक अस्थिर क्षेत्र हो सकता है।
एटॉमिक बुलियन क्या करता है कि एक अस्थिर बूलियन प्राप्त नहीं कर सकता है?
परमाणु * कक्षाएं आपको ऐसे तरीके देती हैं जो अधिक उन्नत कार्यक्षमता प्रदान करते हैं incrementAndGet()
, जैसे कि , compareAndSet()
और अन्य जो लॉकिंग के बिना कई ऑपरेशन (प्राप्त / वृद्धि / सेट, परीक्षण / सेट) लागू करते हैं। इसीलिए परमाणु * वर्ग इतने शक्तिशाली हैं।
उदाहरण के लिए, यदि एकाधिक थ्रेड्स निम्न कोड का उपयोग कर उपयोग कर रहे हैं, तो ++
दौड़ की स्थिति होगी क्योंकि ++
वास्तव में है: प्राप्त करें, वृद्धि, और सेट करें।
private volatile value;
...
// race conditions here
value++;
हालाँकि, निम्न कोड ताले के बिना सुरक्षित रूप से एक बहु-थ्रेडेड वातावरण में काम करेगा:
private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();
यह ध्यान रखना भी महत्वपूर्ण है कि एटॉमिक * क्लास का उपयोग करके अपने वाष्पशील क्षेत्र को लपेटना एक महत्वपूर्ण दृष्टिकोण है, जो किसी वस्तु की दृष्टि से महत्वपूर्ण साझा संसाधन को एनकैप्सुलेट करता है। इसका मतलब यह है कि डेवलपर्स केवल यह मानकर फ़ील्ड के साथ सौदा नहीं कर सकते हैं कि यह साझा नहीं किया गया है संभवतः फ़ील्ड ++ के साथ समस्याओं को इंजेक्ट कर रहा है; या अन्य कोड जो दौड़ की स्थिति का परिचय देते हैं।
यदि क्लास स्तर के चर तक पहुंचने वाले कई धागे हैं, तो प्रत्येक धागा अपने थ्रेडलोकल कैश में उस चर की प्रतिलिपि रख सकता है।
वेरिएबल को अस्थिर बनाने से थ्रेड्स की प्रतिलिपि को थ्रेडलोकल कैश में रखने से रोका जा सकेगा।
परमाणु चर अलग-अलग होते हैं और वे अपने मूल्यों के परमाणु संशोधन की अनुमति देते हैं।
बूलियन आदिम प्रकार लिखने और पढ़ने के संचालन के लिए परमाणु है, अस्थिर पहले-सिद्धांत की गारंटी देता है। इसलिए यदि आपको एक साधारण गेट () और सेट () की आवश्यकता है तो आपको एटॉमिकबुलियन की आवश्यकता नहीं है।
दूसरी तरफ अगर आपको चर के मान को सेट करने से पहले कुछ जांच को लागू करने की आवश्यकता है, जैसे "अगर सच है तो गलत पर सेट है", तो आपको इस ऑपरेशन को परमाणु रूप से भी करने की आवश्यकता है, इस मामले में तुलना का उपयोग करें और इसके द्वारा प्रदान किए गए अन्य तरीके AtomicBoolean, चूंकि यदि आप इस तर्क को अस्थिर बूलियन के साथ लागू करने का प्रयास करते हैं, तो आपको यह सुनिश्चित करने के लिए कुछ सिंक्रनाइज़ेशन की आवश्यकता होगी कि मूल्य प्राप्त और सेट के बीच नहीं बदला गया है।
याद रखें IDIOM -
READ - MODIFY- इसे आप अस्थिरता के साथ प्राप्त नहीं कर सकते
volatile
केवल उन मामलों में काम करता है जहां मालिक थ्रेड में फ़ील्ड मान को अद्यतन करने की क्षमता है और अन्य थ्रेड केवल पढ़ सकते हैं।
यदि आपके पास अपने बूलियन को संशोधित करने वाला केवल एक धागा है, तो आप एक अस्थिर बूलियन का उपयोग कर सकते हैं (आमतौर पर आप इसे परिभाषित करने के लिए ऐसा करते हैंstop
थ्रेड के मुख्य लूप में जाँच की गई चर )।
हालांकि, यदि आपके पास बूलियन को संशोधित करने वाले कई सूत्र हैं, तो आपको एक का उपयोग करना चाहिए AtomicBoolean
। और, निम्न कोड सुरक्षित नहीं है:
boolean r = !myVolatileBoolean;
यह ऑपरेशन दो चरणों में किया जाता है:
एक अन्य धागे के बीच मूल्य को संशोधित करते हैं #1
और 2#
, आप एक गलत परिणाम मिला हो सकता है। AtomicBoolean
विधियाँ इस समस्या को कदम #1
और #2
परमाणु रूप से करने से बचती हैं ।
दोनों एक ही अवधारणा के हैं लेकिन परमाणु बूलियन में यह ऑपरेशन को परमाणुता प्रदान करेगा, जब बीच में सीपीयू स्विच होता है।