2015-03-03 8 views
5

क्या परमाणु रिफरेंस और सिंक्रनाइज़ के बीच कोई अंतर है?
ईजी।परमाणु संदर्भ और सिंक्रनाइज़ के बीच क्या अंतर है?

public class Internet { 
    AtomicReference<String> address; 
    public String getAddress(){ 
     return address.toString(); 
    } 
    public void setAddress(String address) { 
     this.address.set(address); 
    } 

} 

और मैं, कुछ धागे कि एक ही समय में वर्ग इस्तेमाल करने की कोशिश करने के लिए वर्ग पारित यह है कि अगर मैं इस का उपयोग एक ही बात है:

public class Internet { 
    String address; 
    public String getAddress(){ 
     return address; 
    } 
    public void setAddress(String address) { 
     this.address = address; 
    } 
} 

और फिर धागा उपयोग synchronized में कक्षा तक पहुंचने से पहले?

+2

यह वही है, अगर आप यही पूछ रहे हैं। Concurrency मॉडल अलग है। –

+0

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html देखें "इस सरल वर्ग के लिए, सिंक्रनाइज़ेशन एक स्वीकार्य समाधान है। लेकिन अधिक जटिल कक्षा के लिए, हम लायन प्रभाव से बचना चाहेंगे अनावश्यक सिंक्रनाइज़ेशन का। " ऊपर के रूप में, कार्यात्मक रूप से वे वही हैं। – jdv

उत्तर

7

आप पहले उदाहरण में संदर्भ को प्रारंभ नहीं किया, यह शायद होना चाहिए:

public class Internet { 
    AtomicReference<String> address = new AtomicReference<String>(); 
    public String getAddress(){ 
     String s = address.get(); 
     return s == null ? null : s.toString(); 
    } 
    public void setAddress(String address) { 
     this.address.set(address); 
    } 
} 

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

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

public class Internet { 
    private final Object lock = new Object(); 
    private String s; 
    public String getAddress() { 
     synchronized(lock) { 
      return s; 
     } 
    } 
    public void setAddress(String s) { 
     synchronized(lock) { 
      this.s = s; 
     } 
    } 
} 

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

As James says in his answer, सिंक्रनाइज़ेशन के साथ आपके थ्रेड लॉक की प्रतीक्षा कर रहे हैं; कोई टाइमआउट नहीं है, और डेडलॉक संभव है। परमाणु संदर्भ के साथ धागा एक साझा लॉक पर इंतजार के साथ अपना परिवर्तन करता है।

लागू करने के लिए इस ताकि आप सभी लॉकिंग, व्यस्त-प्रतीक्षा, और कैश अद्यतन करने से बच जाएंगे, ताकि आप वस्तु अपरिवर्तनीय बना सकते हैं अपने कोड का आयोजन किया जाएगा सबसे आसान और सबसे अच्छा प्रदर्शन रास्ता:

public final class Internet { 
    private final String s; 
    public Internet(String s) { 
     this.s = s; 
    } 
    public String getAddress() {return s;} 
} 

वरीयता के अवरोही क्रम में:

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

synchronized विधि/ब्लॉक उस विधि/ब्लॉक को अन्य थ्रेड से अवरुद्ध करता है जबकि एक थ्रेड विधि का प्रदर्शन कर रहा है।

एक Atomic... को कई थ्रेडों द्वारा एक बार में एक्सेस किया जा सकता है - आमतौर पर CAS उनके लिए उपलब्ध उच्च विधियों तक पहुंचने के लिए उपलब्ध विधियां उपलब्ध हैं।

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

ये दो वर्ग लगातार बढ़ती संख्या को वापस करने के लिए दो अलग-अलग तरीकों का उपयोग करते हैं, जैसे कि एक ही संख्या दो बार वितरित नहीं की जाएगी। AtomicInteger संस्करण एक उच्च लोड वातावरण में तेजी से चलाएगा। synchronized का उपयोग करने वाला एक जावा 4 और पुराने में काम करेगा।

public class Incremental1 { 

    private AtomicInteger n = new AtomicInteger(); 

    public Integer nextNumber() { 
     // Use the Atomic CAS function to increment the number. 
     return n.getAndIncrement(); 
    } 
} 

public class Incremental2 { 

    private int n = 0; 

    public synchronized Integer nextNumber() { 
     // No two threads can get in here at the same time. 
     return n++; 
    } 

} 
+1

मैंने सोचा कि मैंने जेसीआईपी में पढ़ा है कि आम तौर पर परमाणुओं को कम से कम मध्य विवाद के लिए प्राथमिकता दी जाती है, न कि उच्च लोड के लिए? –

+0

@ नाथन ह्यूजेस - निर्भर करता है कि आप उच्च लोड से क्या मतलब रखते हैं। परमाणु सभी के तहत असाधारण रूप से उच्च भार के तहत अच्छी तरह से काम करते हैं। परमाणुओं का उपयोग करके आपको अक्सर परमाणु और बहुत अधिक भार के नीचे स्पिनलॉक करना पड़ता है, इससे भारी गिरावट हो सकती है लेकिन उन स्थितियों के तहत 'सिंक्रनाइज़' बहुत पहले क्रॉल में गिर जाती। – OldCurmudgeon

+0

@OldCurmudgeon आपका अंतिम विवरण पूरी तरह सत्य नहीं है। उच्च विवाद के तहत 'अवरोधक्यूयू' एक 'ConcurrentLinkedQueue' से बेहतर प्रदर्शन करता है। असफल नहीं होगा, बल्कि थ्रेड शेड्यूलिंग। तो मैं कहूंगा कि नाथन का बयान सही है। –

3

वहाँ अन्य जवाब यहां अगर आप उन्हें समझ सकते हैं के साथ कुछ भी गलत नहीं है, लेकिन वे ज्यादातर विवरण, नामकरण पर ध्यान केंद्रित है, और उपयोग-मामलों, बड़ी तस्वीर के ऊपर लंघन करते हुए लगते हैं कि "हर कोई" पहले से ही जानता है।

यहां बड़ी तस्वीर है --- AtomicFoobar ऑपरेशन और synchronized ब्लॉक के बीच का अंतर।

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

synchronized ब्लॉक, दूसरी ओर यह जटिल है जितना आप इसे बनाते हैं --- लॉक लॉक होने पर कितने कथन निष्पादित किए जाते हैं इसकी कोई सीमा नहीं है। synchronized ब्लॉक कभी असफल रहा, लेकिन कॉलिंग थ्रेड को तब तक इंतजार कर सकता है जब तक ऑपरेशन सुरक्षित रूप से नहीं किया जा सके।

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

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