2010-06-28 11 views
6

मुझे पता है कि जब आप केवल एक थ्रेड द्वारा निष्पादित करने के लिए विधि को लॉक करना चाहते हैं तो आप इसे synchronized कीवर्ड के साथ घोषित करते हैं।सिंक्रनाइज़ किए गए पूरे वर्ग के लिए विधि को कैसे लॉक करें?

कक्षाओं के बारे में क्या, ऑब्जेक्ट्स की पूरी कक्षा पर लॉक कैसे प्रदान करें जब थ्रेड उस कक्षा के उदाहरण पर कुछ कोड निष्पादित कर रहा है?

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

+1

क्या आप समझा सकते हैं कि आपको ऐसा करने की आवश्यकता क्यों है? मुझे एहसास है कि आप गलत समस्या पर हमला कर सकते हैं। विधि कॉल को सिंक्रनाइज़ करने की आवश्यकता * आपके वर्ग के पूरी तरह से अलग उदाहरण * वास्तविक समस्या की तरह लगता है कहीं और है। –

उत्तर

8

आप एक विशिष्ट वस्तु पर सिंक्रनाइज़ या तो कुछ नामित स्थिर ताला वस्तु, या वर्ग वस्तु (जो जब स्थिर तरीकों सिंक्रनाइज़ किए जाने की घोषणा की जाती है होता है):

class X { 
    private static final Object lock = new Object(); 
    public void oneAtATime() { 
     synchronized (lock) { 
      // Do stuff 
     } 
    } 
} 
class Y { 
    public void oneAtATime() { 
     synchronized (Y.class) { 
      // Do stuff 
     } 
    } 
} 

प्रत्येक संस्करण का अपना पक्ष-विपक्ष है ; कक्षा पर लॉकिंग, कोड के बाहर, अन्य कोडों को अपने स्वयं के कारणों के लिए उसी लॉक का उपयोग करने की अनुमति देता है (जो इसे आपके द्वारा प्रदान की जाने वाली तुलना में अधिक उच्च स्तरीय सिंक्रनाइज़ेशन को ऑर्केस्ट्रेट करने की अनुमति देता है) जबकि static final Object lock दृष्टिकोण आपको लॉक करके इसे प्रतिबंधित करने देता है फ़ील्ड प्राइवेट (जो लॉकिंग के बारे में कारण बनाना आसान बनाता है और आपके कोड को डेडलॉकिंग से बचता है क्योंकि किसी और ने खराब कोड लिखा है)।

आप निश्चित रूप से भी कुछ तुल्यकालन तंत्र java.util.concurrent से, स्पष्ट Lock रों है, जो ताला लगा (और ReentrantLock वर्तमान में एक छोटे से उच्च विवाद के तहत निहित ताले तुलना में बेहतर प्रदर्शन) पर अधिक नियंत्रण प्रदान करते हैं की तरह इस्तेमाल कर सकते हैं।


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

कुछ इस तरह के बजाय

:

class Z { 
    private static int state; 
    public void oneAtATime(){ 
     synchronized (Z.class) { 
      state++; 
     } 
    } 
} 

इस तरह करें:

class State { 
    private int value; 
    public synchronized void mutate(){ value++; } 
} 
class Z { 
    private final State state; 
    public Z(State state){ 
     this.state = state; 
    } 
    public void oneAtATime(){ 
     state.mutate(); 
    } 
} 
// Usage: 
State s1 = new State(), s2 = new State(); 
Z foo = new Z(s1); 
Z bar = new Z(s1); 
Z frob = new Z(s2); 
Z quux = new Z(s2); 

अब foo और bar अभी भी एक दूसरे से जुड़े होते हैं, लेकिन वे स्वतंत्र रूप से frob और quux से काम कर सकते हैं।

+0

यह (आखिरी) तरीका लगभग निश्चित रूप से सबसे अच्छा है जो मैं कहूंगा। यह आपके वर्ग के उप-वर्गों के साथ क्या होता है, और आपके कार्यक्रम के कई उदाहरणों के साथ पारदर्शी बनाता है, और स्थिर तरीकों की आवश्यकता होने पर भी सावधान रहना चाहिए। –

2

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

यह एक आक्रामक सिंक्रनाइज़ेशन है, मैं जितना संभव हो उससे बचूंगा।

0

इसके लिए कोई अंतर्निहित तंत्र नहीं है। अपनी खुद की स्थिर लॉक विशेषता बनाएं, और सुनिश्चित करें कि आप इसे लॉक करते हैं और इसे प्रत्येक विधि में अनलॉक करते हैं। अपवादों के बारे में मत भूलना - सुनिश्चित करें कि आप इसे "अंततः" खंडों में अनलॉक करते हैं।

5

यदि आप स्थिर सिंक्रनाइज़ विधियों का उपयोग करते हैं, तो वे क्लास लॉक के माध्यम से बंद हो जाते हैं। तुम भी कक्षा में एक स्थिर वस्तु घोषित करने और ताला है कि एक विधि में मैं की तरह कुछ के माध्यम से विश्वास कर सकते हैं:

private static final Object STATIC_LOCK = new Object(); 

private void foo() { 
    synchronized (STATIC_LOCK) { 
      //do stuff... 
    } 
} 
0

यह काम करना चाहिए:

public class MyClass { 
    void synchronizedMethod() { 
    synchronized (MyClass.class) { 
     // synchronized on static level 
    } 
    } 
} 

कौन सा 'missuses' वर्ग के क्रम-प्रतिनिधित्व के लिए ताला। यह संभव है क्योंकि किसी ऑब्जेक्ट को जावा में म्यूटेक्स के रूप में उपयोग किया जा सकता है।

+0

यह देखते हुए कि स्थिर सिंक्रनाइज़ किए गए तरीके क्लास ऑब्जेक्ट पर सिंक्रनाइज़ करते हैं, तो आप ऐसा दुरुपयोग क्यों करते हैं? –

+0

क्या ऐसा है? इस मामले में, यदि जावा डिजाइनर ऐसा करते हैं, तो शायद यह कोई मिसयूज नहीं है। मैंने सोचा कि सबसे साफ तरीका एक समर्पित स्थिर मॉनीटर/म्यूटेक्स ऑब्जेक्ट होना था, और कुछ ऑब्जेक्ट का उपयोग करना कुछ हद तक हैक है - हालांकि मैं व्यक्तिगत रूप से उस विकल्प को चुनता हूं। मिस्यूज को अब उद्धरण में रखें :) –

2

सिंक्रनाइज़ अपने वर्ग के स्थिर क्षेत्र, या वर्ग पर ही:

synchronized(MyClass.class) { 
     // mutually excluded method body 
} 
1

दोनों धागे तथ्य से

public void someMethod() { 
    synchronized(ClassThatShouldBeProtected.class) { 
    someSynchronizedCode(); 
    } 
} 

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

0

http://www.janeg.ca/scjp/threads/synchronization.html

कई तरीके इसे प्राप्त करने के बारे में बात करती है। सामान्य रूप से , ताले निषिद्ध हैं और थ्रेडिंग के लाभ में बाधा डालते हैं। इसलिए महत्वपूर्ण कोड जितना संभव हो उतना कम किया जाना चाहिए।

क्या आप क्लास लीवर लॉक कक्षा के स्थिर चरों तक पहुंचने के लिए चाहते हैं या यह कक्षा के एक सामान्य बाहरी संसाधन तक पहुंच की सुरक्षा के लिए है? इस मामले में आपको इसे एक्सेस करते समय एक अलग लॉक होना चाहिए।

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

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