आंतरिक और बाहरी सिंक्रनाइज़ेशन का वास्तव में क्या अर्थ है और वे एक-दूसरे से अलग कैसे होते हैं?
बाहरी तुल्यकालन जब फोन करने वाले (आप) synchronized
कीवर्ड या अन्य ताले का उपयोग किसी अन्य वर्ग के खिलाफ की रक्षा करने के लिए एक से अधिक थ्रेड द्वारा पहुँचा जा रहा है। आमतौर पर इसका उपयोग किया जाता है यदि प्रश्न में कक्षा स्वयं सिंक्रनाइज़ नहीं है - SimpleDateFormat
एक प्रमुख उदाहरण है। यदि आप समवर्ती संग्रह से निपटने के दौरान भी थ्रेड के बीच सिग्नलिंग की आवश्यकता होती है तो इसका भी उपयोग किया जा सकता है।
आंतरिक सिंक्रनाइज़ेशन आंतरिक एक (वेक्टर, हैशटेबल इत्यादि) से तेज क्यों है? भले ही वे दोनों एक ही तंत्र का उपयोग करते हैं?
बाहरी तुल्यकालन नहीं जरूरी तेज है। आम तौर पर एक वर्ग निर्धारित कर सकता है जब इसे synchronized
ब्लॉक में सभी विधि कॉल को कॉल करने वाले कॉलर के बजाय कोड के एक महत्वपूर्ण अनुभाग के आसपास सिंक्रनाइज़ करने की आवश्यकता होती है।
आप सामान्य सिफारिश के बारे में नहीं उपयोग Vector
और HashTable
और बदले Collections.synchronizedList(...)
या synchronizedMap(...)
तरीकों का उपयोग करने के लिए बात कर रहे हैं, तो यह क्योंकि Vector
और HashTable
वर्ष/वर्ष पुराने वर्गों के रूप में देखा जाता है। एक लपेटा ArrayList
या HashMap
एक बेहतर समाधान के रूप में देखा जाता है।
कभी-कभी @ क्रिस ने बताया कि बाह्य सिंक्रनाइज़ेशन तेज हो सकता है जब आपको कक्षा में एक दूसरे के बाद कई बदलाव करने की आवश्यकता होती है। एक बार बाहरी रूप से लॉक करके और फिर कक्षा में कई बदलाव करने से, यह आंतरिक रूप से लॉक होने वाले प्रत्येक परिवर्तन से बेहतर काम करता है। एक लॉक एकाधिक लॉक कॉल से तेज होने पर एक पंक्ति में बनाई जाती है।
अगर कोई उदाहरण के साथ समझा सकता है तो यह वास्तव में सहायक होता है।
Vector
के बजाय, आम तौर पर लोग बेहतर प्रदर्शन के रूप में एक लिपटे ArrayList
की अनुशंसा करते हैं। यह गैर-सिंक्रनाइज़ ArrayList
कक्षा को एक रैपर वर्ग में लपेटता है जो बाह्य इसे सिंक्रनाइज़ करता है।
public class Foo {
private int count;
public void addToCount() {
count++;
log.info("count increased to " + count);
}
}
आप बाहरी तुल्यकालन इस्तेमाल कर सकते हैं और addToCount()
के लिए हर कॉल लपेट:
List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());
बनाम सामान्य रूप में बाहरी आंतरिक के संदर्भ में, निम्न वर्ग है कि आप एक से अधिक थ्रेड समवर्ती इसका इस्तेमाल करने की अनुमति देना चाहते हैं पर विचार
synchronized (foo) {
foo.addToCount();
}
या वर्ग ही आंतरिक तुल्यकालन का उपयोग करें और यो के लिए ताला कर सकते हैं: एक synchronized
ब्लॉक में यू। यह बेहतर प्रदर्शन करती है क्योंकि लकड़हारा वर्ग ताला का एक हिस्सा होने की जरूरत नहीं है:
public void addToCount() {
int val;
synchronized (this) {
val = ++count;
}
// this log call should not be synchronized since it does IO
log.info("count increased to " + val);
}
बेशक
, Foo
वर्ग वास्तव में इस मामले में एक AtomicInteger
का उपयोग करें और आंतरिक रूप से अपने स्वयं के reentrance का ध्यान रखना चाहिए:
private final AtomicInteger count = new AtomicInteger(0);
public void addToCount() {
int val = count.incrementAndGet()
log.info("count increased to " + val);
}
मामूली तरफ: सिंक्रनाइज़ संग्रहों का उपयोग करने से थ्रेड-सुरक्षित कोड लिखने के लिए आमतौर पर बहुत बेहतर तरीके होते हैं। (जैसे लॉक-फ्री समवर्ती डेटा स्ट्रक्चर जो अवरुद्ध करने की आवश्यकता नहीं होने पर न्यूनतम ओवरहेड लेते हैं।) – millimoose