परमाणु इंटेगर के लिए व्यावहारिक उपयोग - जावा, समवर्ती, परमाणु

मैं समझता हूं कि परमाणु इंटेगर और अन्य परमाणु चर समवर्ती पहुंच की अनुमति देते हैं। इस वर्ग में आमतौर पर किस मामले में उपयोग किया जाता है?

उत्तर:

उत्तर के लिए 154 № 1

के दो मुख्य उपयोग हैं AtomicInteger:

  • एक परमाणु काउंटर के रूप में (incrementAndGet(), आदि) जो कई धागे द्वारा समवर्ती रूप से उपयोग किया जा सकता है

  • एक आदिम के रूप में समर्थन करता है तुलना और स्वैप निर्देश (compareAndSet()) गैर-अवरुद्ध एल्गोरिदम लागू करने के लिए।

    यहां से गैर-अवरुद्ध यादृच्छिक संख्या जेनरेटर का उदाहरण दिया गया है प्रैक्टिस में ब्रायन गोएट्ज़ की जावा कंसुरेंसी:

    public class AtomicPseudoRandom extends PseudoRandom {
    private AtomicInteger seed;
    AtomicPseudoRandom(int seed) {
    this.seed = new AtomicInteger(seed);
    }
    
    public int nextInt(int n) {
    while (true) {
    int s = seed.get();
    int nextSeed = calculateNext(s);
    if (seed.compareAndSet(s, nextSeed)) {
    int remainder = s % n;
    return remainder > 0 ? remainder : remainder + n;
    }
    }
    }
    ...
    }
    

    जैसा कि आप देख सकते हैं, यह मूल रूप से लगभग उसी तरह काम करता है incrementAndGet(), लेकिन मनमाने ढंग से गणना करता है (calculateNext()) वृद्धि के बजाय (और वापसी से पहले परिणाम को संसाधित करता है)।


जवाब के लिए 83 № 2

पूर्ण सरल उदाहरण मैं सोच सकता हूं कि परमाणु संचालन में वृद्धि करना है।

मानक स्याही के साथ:

private volatile int counter;

public int getNextUniqueIndex() {
return counter++; // Not atomic, multiple threads could get the same result
}

परमाणु इंटेगर के साथ:

private AtomicInteger counter;

public int getNextUniqueIndex() {
return counter.getAndIncrement();
}

उत्तरार्द्ध सभी उत्परिवर्तनों को सिंक्रनाइज़ करने के बिना सरल उत्परिवर्तन प्रभाव (विशेष रूप से गिनती, या अद्वितीय-अनुक्रमण) करने का एक बहुत ही आसान तरीका है।

अधिक जटिल सिंक्रनाइज़ेशन-मुक्त तर्क का उपयोग करके नियोजित किया जा सकता है compareAndSet() आशावादी लॉकिंग के एक प्रकार के रूप में - वर्तमान मूल्य प्राप्त करें, इस पर आधारित परिणाम गणना करें, इस परिणाम को सेट करें iff मान अभी भी गणना करने के लिए उपयोग किया जाने वाला इनपुट है, फिर भी शुरू करें - लेकिन गिनती उदाहरण बहुत उपयोगी हैं, और मैं अक्सर उपयोग करता हूं AtomicIntegers गिनती और वीएम-व्यापी अद्वितीय जनरेटर के लिए यदि एकाधिक धागे शामिल होने का कोई संकेत है, क्योंकि वे "मेरे साथ काम करना इतना आसान हैं" डी लगभग सादा उपयोग करने के लिए समयपूर्व अनुकूलन पर विचार करते हैं ints

जबकि आप लगभग हमेशा एक ही सिंक्रनाइज़ेशन गारंटी प्राप्त कर सकते हैं ints और उपयुक्त है synchronized घोषणा, की सुंदरता AtomicInteger यह है कि थ्रेड-सुरक्षा वास्तविक ऑब्जेक्ट में ही बनाई गई है, इसके बजाय आपको संभावित इंटरलीविंग्स और मॉनीटरों के बारे में चिंता करने की आवश्यकता है, जो कि प्रत्येक विधि का उपयोग करने के लिए होता है int मूल्य। कॉल करते समय गलती से थ्रेडसाफ्टी का उल्लंघन करना बहुत कठिन होता है getAndIncrement() लौटने की तुलना में i++ और मॉनीटर के सही सेट को पहले से प्राप्त करने के लिए याद रखना (या नहीं)।


उत्तर № 3 के लिए 51

यदि आप परमाणु इंटेगर के तरीकों को देखते हैं, तो आप देखेंगे कि वे इनट्स पर सामान्य संचालन के अनुरूप हैं। उदाहरण के लिए:

static AtomicInteger i;

// Later, in a thread
int current = i.incrementAndGet();

इसका धागा-सुरक्षित संस्करण है:

static int i;

// Later, in a thread
int current = ++i;

इस तरह के तरीकों का नक्शा:
++i है i.incrementAndGet()
i++ है i.getAndIncrement()
--i है i.decrementAndGet()
i-- है i.getAndDecrement()
i = x है i.set(x)
x = i है x = i.get()

साथ ही, अन्य सुविधा विधियां भी हैं compareAndSet या addAndGet


जवाब के लिए 31 № 4

का प्राथमिक उपयोग AtomicInteger जब आप एक बहुप्रचारित संदर्भ में होते हैं और आपको बिना किसी पूर्णांक पर थ्रेड सुरक्षित संचालन करने की आवश्यकता होती है synchronized। आदिम प्रकार पर असाइनमेंट और पुनर्प्राप्ति int पहले से ही परमाणु हैं AtomicInteger कई परिचालनों के साथ आता है जो परमाणु नहीं हैं int

सबसे सरल हैं getAndXXX या xXXAndGet। उदाहरण के लिए getAndIncrement() एक परमाणु समकक्ष है i++ जो परमाणु नहीं है क्योंकि यह वास्तव में तीन संचालन के लिए एक छोटा सा कट है: पुनर्प्राप्ति, जोड़ और असाइनमेंट। compareAndSet semaphores, ताले, latches, आदि लागू करने के लिए बहुत उपयोगी है

का उपयोग करते हुए AtomicInteger सिंक्रनाइज़ेशन का उपयोग करके इसे करने से तेज़ और अधिक पठनीय है।

एक साधारण परीक्षण:

public synchronized int incrementNotAtomic() {
return notAtomic++;
}

public void performTestNotAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
incrementNotAtomic();
}
System.out.println("Not atomic: "+(System.currentTimeMillis() - start));
}

public void performTestAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
atomic.getAndIncrement();
}
System.out.println("Atomic: "+(System.currentTimeMillis() - start));
}

जावा 1.6 के साथ मेरे पीसी पर परमाणु परीक्षण 3 सेकंड में चलता है जबकि सिंक्रनाइज़ एक लगभग 5.5 सेकंड में चलता है। यहां समस्या यह है कि सिंक्रनाइज़ करने के लिए ऑपरेशन (notAtomic++) वास्तव में छोटा है। तो सिंक्रनाइज़ेशन की लागत ऑपरेशन की तुलना में वास्तव में महत्वपूर्ण है।

परमाणु के अलावा परमाणु इंटेगर का एक परिवर्तनीय संस्करण के रूप में उपयोग किया जा सकता है Integer उदाहरण के लिए Mapमूल्य के रूप में है।


जवाब के लिए 13 № 5

उदाहरण के लिए, मेरे पास एक पुस्तकालय है जो उत्पन्न करता हैकुछ वर्ग के उदाहरण इन उदाहरणों में से प्रत्येक में एक अद्वितीय पूर्णांक आईडी होना चाहिए, क्योंकि ये उदाहरण सर्वर पर भेजे जाने वाले आदेशों का प्रतिनिधित्व करते हैं, और प्रत्येक कमांड में एक अद्वितीय आईडी होना चाहिए। चूंकि एकाधिक धागे को एक साथ आदेश भेजने की अनुमति है, इसलिए मैं उन आईडी उत्पन्न करने के लिए एक परमाणु इंटेगर का उपयोग करता हूं। एक वैकल्पिक दृष्टिकोण कुछ प्रकार के ताला और नियमित पूर्णांक का उपयोग करना होगा, लेकिन यह धीमा और कम सुरुचिपूर्ण दोनों है।


जवाब के लिए 6 № 6

जावा 8 परमाणु वर्गों को दो रोचक कार्यों के साथ बढ़ा दिया गया है:

  • int getAndUpdate (IntunaryOperator अद्यतन फ़ंक्शन)
  • int updateAndGet (IntUnaryOperator अद्यतन फ़ंक्शन)

दोनों प्रदर्शन करने के लिए अद्यतन समारोह का उपयोग कर रहे हैंपरमाणु मूल्य का अद्यतन। अंतर यह है कि पहला व्यक्ति पुराना मान देता है और दूसरा एक नया मान देता है। मानक एक से अधिक जटिल "तुलना और सेट" संचालन करने के लिए अद्यतन फ़ंक्शन लागू किया जा सकता है। उदाहरण के लिए यह जांच सकता है कि परमाणु काउंटर शून्य से नीचे नहीं जाता है, आमतौर पर इसे सिंक्रनाइज़ेशन की आवश्यकता होती है, और यहां कोड लॉक-फ्री है:

    public class Counter {

private final AtomicInteger number;

public Counter(int number) {
this.number = new AtomicInteger(number);
}

/** @return true if still can decrease */
public boolean dec() {
// updateAndGet(fn) executed atomically:
return number.updateAndGet(n -> (n > 0) ? n - 1 : n) > 0;
}
}

कोड से लिया गया है जावा परमाणु उदाहरण


जवाब के लिए 5 № 7

जैसे गैबोजो ने कहा, कभी-कभी मैं परमाणु इंटेगर्स का उपयोग करता हूंजब मैं संदर्भ से एक int पास करना चाहता हूँ। यह एक अंतर्निर्मित कक्षा है जिसमें आर्किटेक्चर-विशिष्ट कोड है, इसलिए यह किसी भी MutableInteger की तुलना में आसान और संभवतः अधिक अनुकूल है, मैं जल्दी से कोड कर सकता हूं। उस ने कहा, यह कक्षा के दुरुपयोग की तरह लगता है।


जवाब के लिए 4 № 8

जब मुझे देने की ज़रूरत होती है तो मैं आमतौर पर परमाणु इंटेगर का उपयोग करता हूंऑब्जेक्ट्स के लिए आईडी जिन्हें कई धागे से एक्सेस किया जा सकता है या बनाया जा सकता है, और मैं आमतौर पर कक्षा पर एक स्थिर विशेषता के रूप में उपयोग करता हूं जिसे मैं वस्तुओं के निर्माता में एक्सेस करता हूं।


जवाब के लिए 3 № 9

आप परमाणु पूर्णांक या लंबे समय पर तुलना एंड्रैप (सीएएस) का उपयोग कर गैर-अवरुद्ध ताले को कार्यान्वित कर सकते हैं। "टीएल 2" सॉफ्टवेयर ट्रांजैक्शनल मेमोरी पेपर इसका वर्णन करता है:

हम एक विशेष संस्करण वाले लिखने-लॉक को जोड़ते हैंहर लेनदेन स्मृति स्थान अपने सबसे सरल रूप में, संस्करणित लेखन-लॉक एक है लॉक प्राप्त करने के लिए एक सीएएस ऑपरेशन का उपयोग करने वाला एकल शब्द स्पिनलॉक इसे जारी करने के लिए एक दुकान। चूंकि एक को इंगित करने के लिए केवल एक बिट की आवश्यकता होती है कि लॉक लिया जाता है, हम बाकी को लॉक शब्द का उपयोग करते हैं संस्करण संख्या।

यह वर्णन कर रहा है कि पहले परमाणु पढ़ा जाता हैपूर्णांक। इसे एक अनदेखा लॉक-बिट और संस्करण संख्या में विभाजित करें। सीएएस को इसे लॉक-बिट सेट के रूप में लॉक-बिट सेट और अगले संस्करण संख्या के साथ वर्तमान संस्करण संख्या के साथ साफ़ करने के रूप में लिखने का प्रयास करें। लूप जब तक आप सफल न हों और आपके धागे का तालाब हो। लॉक-बिट के साथ वर्तमान संस्करण संख्या को सेट करके अनलॉक करें। पेपर ताले में संस्करण संख्याओं का उपयोग करने का वर्णन करता है ताकि समन्वयित हो सके कि थ्रेड के लिखने पर लगातार पढ़ने का सेट होता है।

यह लेख वर्णन करता है कि प्रोसेसर के पास तुलना करने के लिए हार्डवेयर समर्थन है और स्वैप संचालन बहुत कुशल बनाते हैं। यह भी दावा करता है:

परमाणु चर का उपयोग कर गैर-अवरुद्ध सीएएस-आधारित काउंटर बेहतर है कम से मध्यम विवाद में लॉक-आधारित काउंटर से प्रदर्शन


उत्तर № 10 के लिए 1

कुंजी यह है कि वे समवर्ती पहुंच की अनुमति देते हैं औरसुरक्षित रूप से संशोधन। वे "बहुसंख्यक वातावरण में काउंटर के रूप में आमतौर पर उपयोग किए जाते हैं - उनके परिचय से पहले यह एक उपयोगकर्ता लिखित वर्ग होना था जो सिंक्रनाइज़ किए गए ब्लॉक में विभिन्न विधियों को लपेटता था।


संबंधित सवाल
सबसे लोकप्रिय