जावा में AtomicReference का उपयोग कब करें?


311

हम कब उपयोग करते हैं AtomicReference?

क्या सभी बहुआयामी कार्यक्रमों में वस्तुओं को बनाने की आवश्यकता है?

एक सरल उदाहरण प्रदान करें जहां AtomicReference का उपयोग किया जाना चाहिए।

जवाबों:


215

एक संदर्भ में परमाणु संदर्भ का उपयोग किया जाना चाहिए जहां आपको एक संदर्भ पर सरल परमाणु (यानी थ्रेड-सुरक्षित , गैर-तुच्छ) संचालन करने की आवश्यकता होती है, जिसके लिए मॉनिटर-आधारित सिंक्रनाइज़ेशन उचित नहीं है। मान लीजिए कि आप देखना चाहते हैं कि क्या कोई विशिष्ट फ़ील्ड केवल तभी वस्तु की स्थिति रहती है जब आप अंतिम बार जाँच करते हैं:

AtomicReference<Object> cache = new AtomicReference<Object>();

Object cachedValue = new Object();
cache.set(cachedValue);

//... time passes ...
Object cachedValueToUpdate = cache.get();
//... do some work to transform cachedValueToUpdate into a new version
Object newValue = someFunctionOfOld(cachedValueToUpdate);
boolean success = cache.compareAndSet(cachedValue,cachedValueToUpdate);

परमाणु संदर्भ शब्दार्थ के कारण, आप इसका उपयोग तब भी कर सकते हैं, जब cacheऑब्जेक्ट का उपयोग किए बिना थ्रेड्स के बीच साझा किया जाता है synchronized। सामान्य तौर पर, जब तक आप नहीं जानते कि आप क्या कर रहे हैं, java.util.concurrentबजाए नंगे के बजाय सिंक्रोनाइज़र या फ्रेमवर्क का उपयोग करना बेहतर है Atomic*

दो बेहतरीन डेड-ट्री संदर्भ जो आपको इस विषय से परिचित कराएंगे:

ध्यान दें कि (मुझे नहीं पता कि यह हमेशा सच रहा है) संदर्भ असाइनमेंट (यानी =) स्वयं परमाणु है ( आदिम 64-बिट प्रकारों को अपडेट करना longया जैसे doubleपरमाणु नहीं हो सकता है; लेकिन संदर्भ को अद्यतन करना हमेशा परमाणु है, भले ही यह 64 बिट हो) ) स्पष्ट रूप से उपयोग किए बिना Atomic*जावा भाषा विनिर्देश 3ed
देखें , धारा 17.7


43
अगर मैं गलत हूं तो मुझे सुधारो, लेकिन ऐसा लगता है कि इसकी जरूरत की कुंजी है क्योंकि आपको "तुलनात्मक" करने की आवश्यकता है। यदि मुझे जो कुछ करने की आवश्यकता थी, वह सेट था तो मुझे एटॉमिकऑब्जेक्ट की आवश्यकता नहीं होगी क्योंकि संदर्भ अपडेट स्वयं परमाणु होने के कारण?
21

क्या cache.compareAndSet (कैश्डवैल्यू, someFunctionOfOld (कैश्डवैल्यूऑउपडेट) करना सुरक्षित है)? यानी गणना को इनलाइन करना?
kaqqao 12

4
जावा में @veggen फंक्शन के तर्कों का मूल्यांकन फंक्शन से पहले किया जाता है, इसलिए इनलाइनिंग से इस मामले में कोई फर्क नहीं पड़ता। हां, यह सुरक्षित है।
दिमित्री

29
@sMoZely यह सही है, लेकिन यदि आप उपयोग नहीं कर रहे हैं तो आपको AtomicReferenceचर को चिह्नित करना चाहिए volatileक्योंकि जबकि रनटाइम गारंटी देता है कि संदर्भ असाइनमेंट परमाणु है, संकलक इस धारणा के तहत अनुकूलन कर सकता है कि चर अन्य थ्रेड द्वारा संशोधित नहीं किया जा रहा था।

1
@ BradCupit ध्यान दें कि मैंने कहा "यदि आप उपयोग नहीं कर रहे हैंAtomicReference "; यदि आप इसका उपयोग कर रहे हैं , तो मेरी सलाह होगी कि आप विपरीत दिशा में जाएं और इसे चिह्नित करें finalताकि संकलक अपने अनुसार अनुकूलन कर सके।
kbolino

91

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

सबसे पहले, एक अपरिवर्तनीय वस्तु एक ऐसी वस्तु है जिसे निर्माण के बाद प्रभावी ढंग से नहीं बदला जाता है। अक्सर एक अपरिवर्तनीय वस्तु के तरीके उसी वर्ग के नए उदाहरण लौटाते हैं। कुछ उदाहरणों में लॉन्ग और डबल के रैपर वर्ग, साथ ही स्ट्रिंग, केवल कुछ का नाम शामिल हैं। ( JVM अपरिवर्तनीय वस्तुओं पर प्रोग्रामिंग कंजरेन्सी के अनुसार आधुनिक संगामिति का एक महत्वपूर्ण हिस्सा हैं)।

अगला, क्यों AtomicReference कि साझा मूल्य साझा करने के लिए एक अस्थिर वस्तु से बेहतर है। एक सरल कोड उदाहरण अंतर दिखाएगा।

volatile String sharedValue;
static final Object lock=new Object();
void modifyString(){
  synchronized(lock){
    sharedValue=sharedValue+"something to add";
  }
}

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

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

अन्य विकल्प एक एटॉमिकरफ्रेंस का उपयोग करना है।

public static AtomicReference<String> shared = new AtomicReference<>();
String init="Inital Value";
shared.set(init);
//now we will modify that value
boolean success=false;
while(!success){
  String prevValue=shared.get();
  // do all the work you need to
  String newValue=shared.get()+"lets add something";
  // Compare and set
  success=shared.compareAndSet(prevValue,newValue);
}

अब यह बेहतर क्यों है? ईमानदारी से यह कोड पहले की तुलना में थोड़ा कम साफ है। लेकिन वास्तव में कुछ महत्वपूर्ण है जो परमाणु परमाणु में हुड के नीचे होता है, और यह तुलना और स्वैप है। यह एक एकल सीपीयू निर्देश है, न कि ओएस कॉल, जो स्विच को बनाता है। यह CPU पर एक एकल निर्देश है। और क्योंकि ताले नहीं हैं, ऐसे मामले में कोई संदर्भ स्विच नहीं है जहां लॉक का उपयोग किया जाता है जो और भी अधिक समय बचाता है!

कैच एटॉमिक रिफरेंस के लिए है, इसमें असमान () कॉल का उपयोग नहीं किया जाता है, बल्कि अपेक्षित मूल्य के लिए == तुलना की जाती है। तो सुनिश्चित करें कि उम्मीद लूप में प्राप्त की गई वास्तविक वस्तु है।


14
आपके दो उदाहरण अलग व्यवहार करते हैं। आपको workedएक ही शब्दार्थ प्राप्त करने के लिए लूप करना होगा ।
पर्देटडॉग

5
मुझे लगता है कि आपको AtomicReference constructor के अंदर मूल्य को इनिशियलाइज़ करना चाहिए, अन्यथा आप साझा करने से पहले किसी अन्य थ्रेड को वैल्यू नल देख सकते हैं। (जब तक साझा नहीं किया जाता है। शुरू में एक स्थिर इनिशियलाइज़र चलाया जाता है।)
हेंनो वर्मीलेन

8
अपने दूसरे उदाहरण में, आपको जावा 8 के रूप में कुछ का उपयोग करना चाहिए: साझा.अपडेटएंडगेट ((x) -> (x + "कुछ जोड़ने देता है"); ... जो बार-बार काम करेगा .compareAndSet जब तक यह काम करता है। यह सिंक्रनाइज़ ब्लॉक के बराबर है जो हमेशा सफल होगा। आपको यह सुनिश्चित करने की आवश्यकता है कि आपके द्वारा पास किया गया लंबोदर साइड-इफ़ेक्ट-फ़्री है, हालाँकि इसे कई बार कहा जा सकता है।
टॉम डिबल

2
अस्थिर स्ट्रिंग शेयरवैल्यू बनाने की आवश्यकता नहीं है। रिश्ते से पहले घटित होने के लिए सिंक्रनाइज़ (लॉक) काफी अच्छा है।
जय पंडित

2
"... एक अपरिवर्तनीय वस्तु की स्थिति को बदलें" यहाँ अभेद्य है, क्योंकि शाब्दिक होने के नाते आप एक अपरिवर्तनीय वस्तु की स्थिति को नहीं बदल सकते हैं। उदाहरण एक अपरिवर्तनीय वस्तु उदाहरण से संदर्भ को अलग-अलग में बदलने का प्रदर्शन करता है। मुझे पता है कि यह पांडित्य है लेकिन मुझे लगता है कि यह ध्यान देने योग्य है कि थ्रेड लॉजिक कितना भ्रामक हो सकता है।
मार्क फिलिप्स

30

यहाँ AtomicReference के लिए एक उपयोग मामला है:

इस श्रेणी पर विचार करें जो एक संख्या सीमा के रूप में कार्य करती है, और निम्न और ऊपरी संख्या सीमा को बनाए रखने के लिए अलग-अलग AtmomicInteger चर का उपयोग करती है।

public class NumberRange {
    // INVARIANT: lower <= upper
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);

    public void setLower(int i) {
        // Warning -- unsafe check-then-act
        if (i > upper.get())
            throw new IllegalArgumentException(
                    "can't set lower to " + i + " > upper");
        lower.set(i);
    }

    public void setUpper(int i) {
        // Warning -- unsafe check-then-act
        if (i < lower.get())
            throw new IllegalArgumentException(
                    "can't set upper to " + i + " < lower");
        upper.set(i);
    }

    public boolean isInRange(int i) {
        return (i >= lower.get() && i <= upper.get());
    }
}

सेट्लॉवर और सेटअप दोनों ही चेक-एक्ट-एक्ट सीक्वेंस हैं, लेकिन उन्हें परमाणु बनाने के लिए पर्याप्त लॉकिंग का उपयोग नहीं करते हैं। यदि संख्या सीमा रखती है (0, 10), और एक थ्रेड कॉल सेटओवर (5) जबकि एक और थ्रेड कॉल सेटपर (4), कुछ अशुभ समय के साथ दोनों बसने वालों में चेक पास करेगा और दोनों संशोधनों को लागू किया जाएगा। परिणाम यह है कि रेंज अब (5, 4) एक अमान्य स्थिति रखती है। इसलिए जबकि अंतर्निहित परमाणुइंटर थ्रेड सुरक्षित हैं, समग्र वर्ग नहीं है। यह ऊपरी और निचले सीमा के लिए अलग-अलग एटॉमिकइंटरेयर्स का उपयोग करने के बजाय एक एटॉमिकरेंस का उपयोग करके तय किया जा सकता है।

public class CasNumberRange {
    // Immutable
    private static class IntPair {
        final int lower;  // Invariant: lower <= upper
        final int upper;

        private IntPair(int lower, int upper) {
            this.lower = lower;
            this.upper = upper;
        }
    }

    private final AtomicReference<IntPair> values = 
            new AtomicReference<IntPair>(new IntPair(0, 0));

    public int getLower() {
        return values.get().lower;
    }

    public void setLower(int lower) {
        while (true) {
            IntPair oldv = values.get();
            if (lower > oldv.upper)
                throw new IllegalArgumentException(
                    "Can't set lower to " + lower + " > upper");
            IntPair newv = new IntPair(lower, oldv.upper);
            if (values.compareAndSet(oldv, newv))
                return;
        }
    }

    public int getUpper() {
        return values.get().upper;
    }

    public void setUpper(int upper) {
        while (true) {
            IntPair oldv = values.get();
            if (upper < oldv.lower)
                throw new IllegalArgumentException(
                    "Can't set upper to " + upper + " < lower");
            IntPair newv = new IntPair(oldv.lower, upper);
            if (values.compareAndSet(oldv, newv))
                return;
        }
    }
}

2
यह लेख आपके उत्तर के समान है, लेकिन अधिक जटिल चीजों की गहराई में जाता है। यह दिलचस्प है! ibm.com/developerworks/java/library/j-jtp04186
LppEdd

20

आशावादी तालों को लगाते समय आप एटॉमिक रेफरेंस का उपयोग कर सकते हैं। आपके पास एक साझा ऑब्जेक्ट है और आप इसे 1 से अधिक थ्रेड से बदलना चाहते हैं।

  1. आप साझा किए गए ऑब्जेक्ट की एक प्रति बना सकते हैं
  2. साझा की गई वस्तु को संशोधित करें
  3. आपको यह जांचने की आवश्यकता है कि साझा वस्तु अभी भी पहले जैसी ही है - यदि हाँ, तो संशोधित प्रति के संदर्भ में अपडेट करें।

जैसा कि अन्य सूत्र ने इसे संशोधित किया है और / इन 2 चरणों के बीच संशोधित कर सकते हैं। आपको इसे एक परमाणु ऑपरेशन में करने की आवश्यकता है। यह वह जगह है जहाँ AtomicReference मदद कर सकता है


7

यहाँ एक बहुत ही सरल उपयोग मामला है और इसका धागा सुरक्षा से कोई लेना-देना नहीं है।

लैम्ब्डा इनवोकेशन के बीच एक वस्तु साझा करने के लिए, AtomicReferenceएक विकल्प है :

public void doSomethingUsingLambdas() {

    AtomicReference<YourObject> yourObjectRef = new AtomicReference<>();

    soSomethingThatTakesALambda(() -> {
        yourObjectRef.set(youObject);
    });

    soSomethingElseThatTakesALambda(() -> {
        YourObject yourObject = yourObjectRef.get();
    });
}

मैं यह नहीं कह रहा हूं कि यह अच्छा डिज़ाइन या कुछ भी है (यह सिर्फ एक तुच्छ उदाहरण है), लेकिन अगर आपके पास ऐसा मामला है जहां आपको लैम्बडा इनवोकेशन के बीच एक ऑब्जेक्ट साझा करने की आवश्यकता है, तो AtomicReferenceएक विकल्प है।

वास्तव में आप किसी भी वस्तु का उपयोग कर सकते हैं जो एक संदर्भ रखती है, यहां तक ​​कि एक संग्रह जिसमें केवल एक आइटम है। हालांकि, एटॉमिकरेंस एक सही फिट है।


6

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

कुछ महत्वपूर्ण प्राथमिक तथ्य इस प्रकार हैं। 1> विभिन्न धागे केवल ढेर स्थान में उदाहरण और स्थिर सदस्य चर के लिए चुनाव लड़ सकते हैं। 2> वाष्पशील पढ़ना या लिखना पूरी तरह से परमाणु और क्रमबद्ध / पहले होता है और केवल स्मृति से किया जाता है। यह कहने से मेरा तात्पर्य यह है कि कोई भी पढ़ा हुआ पिछला लेख मेमोरी में फॉलो करेगा। और कोई भी लेख स्मृति से पिछले पढ़ने का पालन करेगा। तो एक अस्थिर के साथ काम करने वाले किसी भी धागे को हमेशा सबसे अद्यतित मूल्य दिखाई देगा। AtomicReference अस्थिरता की इस संपत्ति का उपयोग करता है।

निम्नलिखित परमाणु अणु के स्रोत कोड के कुछ हैं। परमाणु संदर्भ एक वस्तु संदर्भ को संदर्भित करता है। यह संदर्भ नीचे के रूप में AtomicReference उदाहरण में एक अस्थिर सदस्य चर है।

private volatile V value;

get () वेरिएबल का नवीनतम मान लौटाता है (जैसा कि वाष्पशील "तरीके से पहले होता है")।

public final V get()

निम्नलिखित परमाणु अनुसंधान का सबसे महत्वपूर्ण तरीका है।

public final boolean  compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

तुलना एएंडसेट (उम्मीद, अपडेट) विधि जावा के असुरक्षित वर्ग की तुलना एएंडस्वापओबजेक्ट () विधि कहती है। असुरक्षित का यह तरीका कॉल देशी कॉल को आमंत्रित करता है, जो प्रोसेसर को एक निर्देश देता है। "उम्मीद" और "अद्यतन" प्रत्येक संदर्भ एक वस्तु।

यदि और केवल अगर AtomicReference उदाहरण के सदस्य चर "मान" को संदर्भित करता है उसी वस्तु को "उम्मीद" से संदर्भित किया जाता है, तो "अपडेट" को इस उदाहरण चर में सौंपा गया है, और "सही" वापस आ गया है। वरना झूठा लौटा दिया जाता है। पूरी बात परमाणु से की गई है। कोई दूसरा धागा बीच में नहीं रोक सकता। चूंकि यह एक एकल प्रोसेसर ऑपरेशन (आधुनिक कंप्यूटर वास्तुकला का जादू) है, यह अक्सर एक सिंक्रनाइज़ ब्लॉक का उपयोग करने की तुलना में तेज़ है। लेकिन याद रखें कि जब कई चर को परमाणु रूप से अद्यतन करने की आवश्यकता होती है, तो AtomicReference मदद नहीं करेगा।

मैं एक पूर्ण विकसित कोड जोड़ना चाहूंगा, जिसे ग्रहण में चलाया जा सकता है। यह कई भ्रम को साफ करेगा। यहां 22 उपयोगकर्ता (MyTh threads) 20 सीटें बुक करने की कोशिश कर रहे हैं। निम्नलिखित कोड स्निपेट है जिसके बाद पूर्ण कोड होता है।

कोड स्निपेट जहां 22 उपयोगकर्ता 20 सीटें बुक करने की कोशिश कर रहे हैं।

for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }

निम्नलिखित पूर्ण चलने वाला कोड है।

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class Solution {

    static List<AtomicReference<Integer>> seats;// Movie seats numbered as per
                                                // list index

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        seats = new ArrayList<>();
        for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }
        for (Thread t : ths) {
            t.join();
        }
        for (AtomicReference<Integer> seat : seats) {
            System.out.print(" " + seat.get());
        }
    }

    /**
     * id is the id of the user
     * 
     * @author sankbane
     *
     */
    static class MyTh extends Thread {// each thread is a user
        static AtomicInteger full = new AtomicInteger(0);
        List<AtomicReference<Integer>> l;//seats
        int id;//id of the users
        int seats;

        public MyTh(List<AtomicReference<Integer>> list, int userId) {
            l = list;
            this.id = userId;
            seats = list.size();
        }

        @Override
        public void run() {
            boolean reserved = false;
            try {
                while (!reserved && full.get() < seats) {
                    Thread.sleep(50);
                    int r = ThreadLocalRandom.current().nextInt(0, seats);// excludes
                                                                            // seats
                                                                            //
                    AtomicReference<Integer> el = l.get(r);
                    reserved = el.compareAndSet(null, id);// null means no user
                                                            // has reserved this
                                                            // seat
                    if (reserved)
                        full.getAndIncrement();
                }
                if (!reserved && full.get() == seats)
                    System.out.println("user " + id + " did not get a seat");
            } catch (InterruptedException ie) {
                // log it
            }
        }
    }

}    

5

हम AtomicReference का उपयोग कब करते हैं?

AtomicReference तुल्यकालिककरण के उपयोग के बिना atomically चर मूल्य को अद्यतन करने के लिए लचीला तरीका है।

AtomicReference एकल चर पर लॉक-थ्रेड-थ्रेड सुरक्षित प्रोग्रामिंग का समर्थन करें।

उच्च स्तर के समवर्ती एपीआई के साथ थ्रेड सुरक्षा प्राप्त करने के कई तरीके हैं । परमाणु चर कई विकल्पों में से एक है।

Lock ऑब्जेक्ट लॉकिंग मुहावरों का समर्थन करते हैं जो कई समवर्ती अनुप्रयोगों को सरल बनाते हैं।

Executorsथ्रेड को लॉन्च करने और प्रबंधित करने के लिए एक उच्च-स्तरीय एपीआई को परिभाषित करें। Java.util.concurrent द्वारा प्रदान किए गए निष्पादन कार्यान्वयन बड़े पैमाने के अनुप्रयोगों के लिए उपयुक्त थ्रेड पूल प्रबंधन प्रदान करते हैं।

समवर्ती संग्रह डेटा के बड़े संग्रह को प्रबंधित करना आसान बनाते हैं, और सिंक्रनाइज़ेशन की आवश्यकता को बहुत कम कर सकते हैं।

परमाणु चर में ऐसी विशेषताएं होती हैं जो सिंक्रनाइज़ेशन को कम करती हैं और मेमोरी संगतता त्रुटियों से बचने में मदद करती हैं।

एक सरल उदाहरण प्रदान करें जहां AtomicReference का उपयोग किया जाना चाहिए।

के साथ नमूना कोड AtomicReference:

String initialReference = "value 1";

AtomicReference<String> someRef =
    new AtomicReference<String>(initialReference);

String newReference = "value 2";
boolean exchanged = someRef.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);

क्या सभी बहुआयामी कार्यक्रमों में वस्तुओं को बनाने की आवश्यकता है?

आपको AtomicReferenceसभी बहु थ्रेडेड प्रोग्राम में उपयोग करने की आवश्यकता नहीं है ।

यदि आप किसी एकल चर की रक्षा करना चाहते हैं, तो उपयोग करें AtomicReference। यदि आप एक कोड ब्लॉक की रक्षा करना चाहते हैं, तो अन्य निर्माण जैसे Lock/ synchronizedआदि का उपयोग करें ।


-1

एक और सरल उदाहरण एक सत्र वस्तु में एक सुरक्षित धागा संशोधन करना है।

public PlayerScore getHighScore() {
    ServletContext ctx = getServletConfig().getServletContext();
    AtomicReference<PlayerScore> holder 
        = (AtomicReference<PlayerScore>) ctx.getAttribute("highScore");
    return holder.get();
}

public void updateHighScore(PlayerScore newScore) {
    ServletContext ctx = getServletConfig().getServletContext();
    AtomicReference<PlayerScore> holder 
        = (AtomicReference<PlayerScore>) ctx.getAttribute("highScore");
    while (true) {
        HighScore old = holder.get();
        if (old.score >= newScore.score)
            break;
        else if (holder.compareAndSet(old, newScore))
            break;
    } 
}

स्रोत: http://www.ibm.com/developerworks/library/j-jtp09238/index.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.