क्या किसी अन्य सिंक्रोनाइज़ की गई विधि से सिंक्रोनाइज़ की गई विधि को कॉल करना सुरक्षित है?


81

यदि एक सिंक्रनाइज़ विधि एक और सिंक्रनाइज़ विधि को कॉल करती है, तो क्या यह थ्रेड सुरक्षित है?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}

क्या यह लेख उत्तर देने में मदद करेगा, या आप कहां उलझन में हैं? kalyanchakravarthy.net/?p=413
जेम्स ब्लैक

हां - आपको वास्तव में इसके संदर्भ में केवल तथाकथित कहे गए तरीके के रूप में पद्धति 2 को चिह्नित करने की आवश्यकता नहीं है।
डिब्रेसरी

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

उत्तर के रूप में मैं जो अनुमान लगाता हूं वह वास्तविक प्रश्न है: हाँ, सिंक्रनाइज़ किए गए कीवर्ड पुनरावर्ती ताले का उपयोग करता है; आप किसी अन्य सिंक्रनाइज़ किए गए विधि से सुरक्षित रूप से कॉल कर सकते हैं।
ब्रेट कैल

थोड़ी देर हो गई है, लेकिन यह अभी भी Google पर पहली हिट है, इसलिए: हाँ, एक ही ऑब्जेक्ट पर सिंक्रनाइज़ किए गए ब्लॉक / विधियां रीवेंटेंट हैं। stackoverflow.com/questions/12219376/reentrant-synchronization
ज़ियाक्सके

जवाबों:


103

हां, जब आप तरीकों को चिह्नित करते हैं synchronized, तो आप वास्तव में ऐसा कर रहे हैं:

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

जब मेथड 1 से मेथड कॉल थ्रेड 2 में हो जाता है, तो यह सुनिश्चित करेगा कि यह लॉक को पकड़ता है this, जिसे यह पहले से ही है, और फिर यह गुजर सकता है।

जब थ्रेड सीधे मेथ 1 या मेथड 2 में जाता है, तो यह तब तक ब्लॉक रहेगा जब तक यह लॉक ( this) प्राप्त नहीं कर सकता है , और फिर यह प्रवेश करेगा।

जैसा कि जेम्स ब्लैक ने टिप्पणियों में कहा है, आपको विधि बॉडी के अंदर क्या करना है, इसके बारे में जागरूक होना चाहिए।

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

अचानक यह थ्रेड सुरक्षित नहीं है क्योंकि आप ConcurrentModificationExceptionअपने भविष्य को देख रहे हैं क्योंकि method3यह अनसिंक्रनाइज़ है, और इस तरह थ्रेड ए द्वारा कॉल किया जा सकता है जबकि थ्रेड बी में काम कर रहा है method1


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

@ user3140993 यहां कोड में गतिरोध के लिए कोई मौका नहीं है। method3असुरक्षित थ्रेडिंग ऑपरेशन दिखाता है, लेकिन आप रीक्रेंट सिंक्रोनाइज़ेशन के बारे में हाजिर हैं।
पिक

7

एक विधि है जिसे सिंक्रोनाइज़्ड कॉल के साथ चिह्नित किया जाता है जो एक अन्य सिंक्रनाइज़ विधि थ्रेड सुरक्षित है।

सामान्य तौर पर, यह कहना संभव नहीं है। यह इस बात पर निर्भर करता है कि विधियां क्या करती हैं, और उसी और अन्य वर्गों पर अन्य विधियां क्या करती हैं।

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


2

जावा ट्यूटोरियल साइट से http://download.oracle.com/javase/tutorial/essential/concurrency/syncmn.html

  1. इंटरलेव के लिए एक ही वस्तु पर सिंक्रनाइज़ किए गए तरीकों के दो आह्वान संभव नहीं है। जब कोई थ्रेड किसी ऑब्जेक्ट के लिए एक सिंक्रोनाइज़ की गई विधि को निष्पादित कर रहा होता है, तो अन्य सभी थ्रेड्स जो ऑब्जेक्ट के साथ पहले थ्रेड को निष्पादित करने तक एक ही ऑब्जेक्ट ब्लॉक (सस्पेंड निष्पादन) के लिए सिंक्रनाइज़ किए गए तरीकों को लागू करते हैं।

  2. जब कोई सिंक्रनाइज़ किए गए तरीके से बाहर निकलता है, तो यह स्वचालित रूप से एक ही ऑब्जेक्ट के लिए सिंक्रनाइज़ विधि के किसी भी बाद के आह्वान के साथ होता है-पहले संबंध स्थापित करता है। यह गारंटी देता है कि ऑब्जेक्ट की स्थिति में परिवर्तन सभी थ्रेड्स को दिखाई देते हैं

इसलिए जावा यह सुनिश्चित करेगा कि यदि 2 थ्रेड्स एक ही विधि को निष्पादित कर रहे हैं, तो विधियाँ समान रूप से निष्पादित नहीं होंगी, लेकिन एक के बाद एक।

लेकिन आपको Lience की समस्या के बारे में पता होना चाहिए, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

और यह भी कि क्या आप uncessarily ताला लगा रहे हैं, कोड में कारण आप का इस्तेमाल किया यह जो पूरी वस्तु ताले, यदि आपका वस्तु केवल एक चर करने के लिए सिंक उपयोग की जरूरत है आप सिर्फ इतना है कि चर ताला चाहिए।


@ स्टीफन ली - आप एक वैरिएबल को लॉक नहीं कर सकते। फिर आप कहते हैं कि synchronized (this.someVar)आप उस वस्तु को देख रहे हैं जिसका संदर्भ इसमें रखा गया है someVar। भेद बहुत महत्वपूर्ण है।
स्टीफन C
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.