मैं जॉन की एक टिप्पणी से सहमत हूं: आपको चर के संदर्भ परिवर्तनों के मामले में विसंगतियों को रोकने के लिए गैर-अंतिम चर का उपयोग करते हुए हमेशा एक अंतिम लॉक डमी का उपयोग करना चाहिए । तो किसी भी मामले में और अंगूठे के पहले नियम के रूप में:
नियम # 1: यदि कोई क्षेत्र गैर-अंतिम है, तो हमेशा (निजी) अंतिम लॉक डमी का उपयोग करें।
कारण # 1: आप लॉक को पकड़ते हैं और चर के संदर्भ को अपने आप से बदल देते हैं। सिंक्रनाइज़ लॉक के बाहर प्रतीक्षा कर रहा एक और धागा पहरेदार ब्लॉक में प्रवेश करने में सक्षम होगा।
कारण # 2: आप लॉक को पकड़ते हैं और एक अन्य थ्रेड वैरिएबल के संदर्भ को बदल देता है। परिणाम समान है: एक और धागा संरक्षित ब्लॉक में प्रवेश कर सकता है।
लेकिन अंतिम लॉक डमी का उपयोग करते समय, एक और समस्या है : आपको गलत डेटा मिल सकता है, क्योंकि आपके गैर-अंतिम ऑब्जेक्ट को केवल सिंक्रनाइज़ (ऑब्जेक्ट) कहते समय रैम के साथ सिंक्रनाइज़ किया जाएगा। इसलिए, अंगूठे के दूसरे नियम के रूप में:
नियम # 2: एक गैर-अंतिम वस्तु को लॉक करते समय आपको हमेशा दोनों करने की आवश्यकता होती है: अंतिम चरण डमी का उपयोग करना और रैम सिंक्रनाइज़ेशन के लिए गैर-अंतिम ऑब्जेक्ट का लॉक। (एकमात्र विकल्प ऑब्जेक्ट के सभी क्षेत्रों को अस्थिर घोषित करेगा!)
इन तालों को "नेस्टेड लॉक" भी कहा जाता है। ध्यान दें कि आपको उन्हें हमेशा उसी क्रम में कॉल करना होगा, अन्यथा आपको एक डेड लॉक मिलेगा :
public class X {
private final LOCK;
private Object o;
public void setO(Object o){
this.o = o;
}
public void x() {
synchronized (LOCK) {
synchronized(o){
}
}
}
}
जैसा कि आप देख सकते हैं कि मैं दो ताले सीधे एक ही पंक्ति पर लिखता हूं, क्योंकि वे हमेशा एक साथ होते हैं। इस तरह, आप 10 नेस्टिंग लॉक भी कर सकते हैं:
synchronized (LOCK1) {
synchronized (LOCK2) {
synchronized (LOCK3) {
synchronized (LOCK4) {
}
}
}
}
ध्यान दें कि यह कोड नहीं टूटेगा यदि आप synchronized (LOCK3)
किसी अन्य थ्रेड्स की तरह केवल एक आंतरिक लॉक प्राप्त करते हैं । लेकिन यह टूट जाएगा यदि आप किसी अन्य धागे में कुछ इस तरह कहते हैं:
synchronized (LOCK4) {
synchronized (LOCK1) {
synchronized (LOCK3) {
synchronized (LOCK2) {
}
}
}
}
गैर-अंतिम फ़ील्ड को हैंडल करते समय ऐसे नेस्टेड लॉक के चारों ओर केवल एक वर्कअराउंड है:
नियम # 2 - वैकल्पिक: ऑब्जेक्ट के सभी क्षेत्रों को अस्थिर के रूप में घोषित करें। (मैं ऐसा करने के नुकसान के बारे में यहां बात नहीं करूंगा, जैसे कि एक्स-लेवल कैश में किसी भी स्टोरेज को रीड्स, एसो के लिए रोकना।)
इसलिए aioobe काफी सही है: बस java.util.concurrent का उपयोग करें। या सिंक्रनाइज़ेशन के बारे में सब कुछ समझना शुरू करें और इसे नेस्टेड ताले के साथ खुद करें। ;)
अधिक विवरण के लिए, गैर-अंतिम फ़ील्ड पर सिंक्रनाइज़ेशन क्यों टूट जाता है, मेरे परीक्षण मामले पर नज़र डालें: https://stackoverflow.com/a/21460055/2012947
और अधिक जानकारी के लिए आपको रैम और कैश के कारण सभी चीजों को सिंक्रनाइज़ करने की आवश्यकता क्यों है, यहां एक नज़र डालें: https://stackoverflow.com/a/21409975/2012947
o
उस समय अनन्य ऑब्जेक्ट के साथ चलता है जिस समय सिंक्रनाइज़ किए गए ब्लॉक तक पहुंच गया था। यदि ऑब्जेक्ट जोo
परिवर्तनों को संदर्भित करता है, तो एक और धागा साथ आ सकता है और सिंक्रनाइज़ कोड ब्लॉक को निष्पादित कर सकता है।