2012-03-01 22 views
25

जावा में, यदि एक तुल्यकालन विधि के लिए एक कॉल में शामिल है एक गैर सिंक्रनाइज़, एक और तरीका अभी भी गैर-सिंक्रनाइज़ विधि का उपयोग कर सकते है एक ही समय में? असल में जो मैं पूछ रहा हूं वह सिंक्रनाइज़ विधि में सबकुछ है उस पर एक ताला है (अन्य सिंक्रनाइज़ किए गए तरीकों के लिए कॉल सहित)? बहुत बहुत धन्यवादएक तुल्यकालन विधि किसी अन्य गैर सिंक्रनाइज़ प्रणाली को बुलाती है, वहाँ गैर सिंक्रनाइज़ पद्धति पर एक ताला

+2

मेरे उत्तर पर कोई प्रतिक्रिया? अगर यह आपकी मदद करता है तो कृपया इसे स्वीकार करें। – Gray

+0

मुझे लगता है कि ग्रे का जवाब स्वीकार किया जाना चाहिए क्योंकि यह ठीक से उत्तर दिया जाता है। – Sankalp

उत्तर

45

यदि आप synchronized विधि में हैं, तो अन्य विधियों द्वारा synchronized पर अन्य विधियों को भी लॉक कर दिया गया है। हालांकि गैर सिंक्रनाइज़ तरीकों के लिए कॉल द्वारा अन्य थ्रेड नहीं बंद कर दिया होंगे - कोई भी एक ही समय में उन्हें फोन कर सकते हैं।

public synchronized void someSynchronizedMethod() { 
    ... 
    someNonSynchronizedMethod(); 
    ... 
} 

// anyone can call this method even if the someSynchronizedMethod() method has 
// been called and the lock has been locked 
public void someNonSynchronizedMethod() { 
    ... 
} 

इसके अलावा, अगर आप someSynchronizedMethod() फोन लेकिन someNonSynchronizedMethod() विधि के भीतर होना होता है, तब भी आप ताला पकड़ो। जब आप सिंक्रनाइज़ किए गए ब्लॉक में प्रवेश करते हैं तो लॉक सक्षम होता है और जब आप उस विधि से बाहर निकलते हैं तो अक्षम होता है। आप अन्य सभी सिंक्रनाइज़ किए गए तरीकों को कॉल कर सकते हैं और वे अभी भी लॉक हो जाएंगे।

लेकिन आप अपने प्रश्न में दो अलग बातें कह रहे हैं:

जावा में, यदि एक तुल्यकालन विधि ही में एक गैर सिंक्रनाइज़ गैर सिंक्रनाइज़ विधि, एक और तरीका अभी भी उपयोग कर सकते हैं के लिए एक कॉल शामिल पहर?

हां। अन्य विधियां गैर-सिंक्रनाइज़ विधियों तक पहुंच सकती हैं।

असल में जो मैं पूछ रहा हूं वह सिंक्रनाइज़ विधि में सब कुछ है (इसमें अन्य सिंक्रनाइज़ किए गए तरीकों के लिए कॉल सहित) है?

उह, हाँ। सिंक्रनाइज़ तरीकों के अन्य कॉल बंद हैं। लेकिन गैर सिंक्रनाइज़ किए गए तरीकों को बंद नहीं किया गया है।

यह भी याद रखें कि यदि विधि static है तो लॉक Class ऑब्जेक्ट ClassLoader में है।

// this locks on the Class object in the ClassLoader 
public static synchronized void someStaticMethod() { 

यदि विधि एक उदाहरण विधि है तो लॉक कक्षा के उदाहरण पर है।

// this locks on the instance object that contains the method 
public synchronized void someInstanceMethod() { 

उन 2 मामलों में 2 अलग-अलग ताले हैं।

आखिरकार, जब आप synchronized उदाहरण विधियों से निपट रहे हैं, तो कक्षा के प्रत्येक इंस्टेंस लॉक किया गया है। इसका मतलब यह है दो धागे अलग उदाहरणों साथ एक ही समय में एक ही synchronized विधि में हो सकता है। लेकिन अगर 2 धागे एक ही उदाहरण पर synchronized तरीकों पर संचालित करने के लिए प्रयास करते हैं, जब तक अन्य एक विधि बाहर निकालता है रोकेंगे।

+0

तो मुझे लगता है कि सिंक्रनाइज़ किए गए लोगों के भीतर गैर-सिंक्रनाइज़ किए गए तरीकों को कॉल करना अच्छा नहीं होगा ... क्योंकि उन्हें किसी अन्य विधि द्वारा एक ही समय में बुलाया जा सकता है। – dido

+3

यदि यह 2 थ्रेड्स को डेटा तक पहुंचने का कारण बनता है जिसे सिंक्रनाइज़ करने की आवश्यकता होती है, तो हाँ, यह एक अच्छा विचार नहीं है। हालांकि, यह हर समय 'toString()' और अन्य विधियों के साथ होता है। यह सिर्फ आपकी वस्तु और उपयोग के मामले पर निर्भर करता है। – Gray

+1

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

2

यदि थ्रेड ए कॉल सिंक्रनाइज़ विधि एम 1 कॉल करता है जो बदले में अनसंक्रनाइज़ विधि एम 2 कॉल करता है, तो थ्रेड बी अभी भी अवरुद्ध किए बिना एम 2 को कॉल कर सकता है।

सिंक्रनाइज़ विधि उस ऑब्जेक्ट पर आंतरिक लॉक प्राप्त करती है और रिलीज़ करती है जिस पर इसे कहा जाता है। यही कारण है कि यह ब्लॉक कर सकता है। अनसंक्रनाइज़ विधि किसी लॉक को प्राप्त करने का प्रयास नहीं करती है (जब तक यह कोड में स्पष्ट रूप से नहीं किया जाता है)।

इस प्रकार, यदि आपको एम 2 के लिए पारस्परिक बहिष्करण सुनिश्चित करने की आवश्यकता है, तो आपको इसके कॉलर (जैसे एम 1) सिंक्रनाइज़ किए गए हैं या नहीं, इस पर ध्यान दिए बिना इसे सिंक्रनाइज़ करना चाहिए।

0

लॉक धागा से संबंधित है, विधि (या अधिक सटीक, इसके ढेर फ्रेम) के लिए नहीं है। ऐसा इसलिए होता है कि यदि आपके पास सिंक्रनाइज़ विधि है, तो आपको गारंटी है कि विधि के प्रारंभ होने से पहले थ्रेड लॉक का मालिक होगा, और बाद में इसे रिलीज़ करेगा।

एक और धागा अभी भी दूसरी, गैर सिंक्रनाइज़ विधि का आह्वान कर सकता है। किसी भी थ्रेड द्वारा किसी भी समय एक अनसंक्रनाइज़ विधि को बुलाया जा सकता है।

2

लॉक धागे से संबंधित नहीं है। लॉक वास्तव में ऑब्जेक्ट (या क्लास लेवल लॉक के मामले में कक्षा) से संबंधित है, और एक धागा एक सिंक्रनाइज़ संदर्भ के भीतर ऑब्जेक्ट (या क्लास लेवल लॉक के मामले में कक्षा) पर लॉक प्राप्त करता है। अब, जावा में कोई लॉक प्रचार नहीं है क्योंकि ऊपर चर्चा की गई है। यहां एक छोटा डेमो है:

सार्वजनिक वर्ग TestThread {

/** 
* @param args 
* @throws InterruptedException 
*/ 
public static void main(String[] args) throws InterruptedException { 
    // TODO Auto-generated method stub 
    ThreadCreator1 threadCreator1 = new ThreadCreator1(); 
    ThreadCreator2 threadCreator2 = new ThreadCreator2(); 

    Thread t1 = new Thread(threadCreator1,"Thread 1"); 
    Thread t3 = new Thread(threadCreator1,"Thread 3"); 
    Thread t2 = new Thread(threadCreator2,"Thread 2"); 

    t1.start(); 
    Thread.sleep(2000); 
    t3.start(); 

} 

}

सार्वजनिक वर्ग ThreadCreator1 लागू करता Runnable {

private static final Task task= new Task(); 
private static final Task2 task2= new Task2(); 

@Override 

public void run() { 

    try { 

     if(Thread.currentThread().getName().equals("Thread 1")) 
      task.startTask2(task2); 
     if(Thread.currentThread().getName().equals("Thread 3")) 
      task2.startTask(); 

    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    // TODO Auto-generated method stub 

    /**/ 

    } 
} 

सार्वजनिक वर्ग टास्क {

public static final Task task = new Task(); 
public static List<String> dataList = new ArrayList<String>(); 
ReentrantLock lock = new ReentrantLock(); 



public void startTask2(Task2 task2) throws InterruptedException 
{ 

    try{ 

     lock.lock(); 
     //new Task2().startTask(); 
     task2.startTask(); 
    } 
    catch(Exception e) 
    { 

    } 
    finally{ 
     lock.unlock(); 
    } 
} 

}

सार्वजनिक वर्ग Task2 {

ReentrantLock lock = new ReentrantLock(); 
public void startTask() throws InterruptedException 
{ 

    try{ 
     //lock.lock(); 
     for(int i =0 ;i< 10;i++) 
    { 
     System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName()); 
     Thread.sleep(1000); 
    } 
    } 
    catch(Exception e) 
    { 

    } 
    /*finally 
    { 
     lock.unlock(); 
    }*/ 
} 

}

बस मैं रैत्रांत का इस्तेमाल किया है यहाँ ताला। यदि उपर्युक्त कोड चलाया गया है, तो थ्रेड 1 और थ्रेड 3 के बीच इंटरलिविंग होगा, लेकिन यदि टास्क 2 क्लास का लॉक हिस्सा असम्बद्ध है, तो कोई इंटरलिविंग नहीं होगा और पहले लॉक प्राप्त करने वाला थ्रेड पूरी तरह से पूरा हो जाएगा, तो यह ताला जारी करेगा और फिर दूसरा धागा आगे बढ़ सकता है।