2012-02-08 14 views
26

का उपयोग इसलिए मैं synchronized कीवर्ड के साथ परीक्षण कर रहा था।जावा सीखना, सिंक्रनाइज़ किए गए कीवर्ड

public class MyTest { 
    static int i = 0; 
    public static void main(String[] args) { 
     new Thread(t1).start(); 
     new Thread(t2).start(); 
    } 

    private static void countMe(String name){ 
     i++; 
     System.out.println("Current Counter is: " + i + ", updated by: " + name); 
    } 

    private static Runnable t1 = new Runnable() { 
     public void run() { 
      try{ 
       for(int i=0; i<5; i++){ 
        countMe("t1"); 
       } 
      } catch (Exception e){} 

     } 
    }; 

    private static Runnable t2 = new Runnable() { 
     public void run() { 
      try{ 
       for(int i=0; i<5; i++){ 
        countMe("t2"); 
       } 
      } catch (Exception e){} 
     } 
    }; 
} 

जब मैंने इसे चलाने के लिए, दो धागे से countMe() विधि बुला के उत्पादन में इस उत्पादन उत्पन्न करता है:

Current Counter is: 1 
Current Counter is: 2 
Current Counter is: 4 
Current Counter is: 5 
Current Counter is: 6 
Current Counter is: 7 
Current Counter is: 3 
Current Counter is: 8 
Current Counter is: 9 
Current Counter is: 10 

और जब मैं करने के लिए विधि countMe() बदलने के लिए:

यहाँ एक उदाहरण है कि मैं करने की कोशिश की है

Current Counter is: 1 
Current Counter is: 2 
Current Counter is: 3 
Current Counter is: 4 
Current Counter is: 5 
Current Counter is: 6 
Current Counter is: 7 
Current Counter is: 8 
Current Counter is: 9 
Current Counter is: 10 
01:
private synchronized static void countMe(){ 
     i++; 
     System.out.println("Current Counter is: " + i); 
} 

मैं इस आउटपुट प्राप्त

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

धन्यवाद।

संपादित करें: एक और बात यह है कि मैं के साथ उलझन में हूँ कि पहली उत्पादन क्यों काउंटर 7. के बाद 3 के लिए गया था यह मेरे लिए थोड़ा असंभव लगता है, लेकिन इसी तरह के परिणाम हर बार जब मैं कोशिश हो कर में, यह सामान्य है है ?

+0

कोई गारंटी नहीं है कि थ्रेड वैकल्पिक होंगे। थ्रेड जो 3 गिना जाता है, तब तक मुद्रित नहीं हो सकता है जब तक कि अन्य धागे की गणना 7 के बाद न हो। –

+0

धन्यवाद, लेकिन 7 के बाद की तरह अगला कॉल प्रिंट 3 कैसे हो सकता है। मेरा मतलब है कि यह 6 या 5 तक प्रिंट कर सकता है, लेकिन ऐसा लगता है कि यह नई विधि कॉल मैंने 3 के बाद पढ़ा नहीं, यह बहुत अजीब लगता है। तो आपको लगता है कि जब भी मुझे 2 या अधिक धागे से कोड के समान ब्लॉक का उपयोग करना होता है तो हमेशा सिंक्रनाइज़ेशन का उपयोग करना बुद्धिमान होना चाहिए ?? – 911TurboS

+5

मेरा सुझाव है कि आप धागे के नाम को प्रिंट करें और यह भ्रम कहां है, यह और अधिक स्पष्ट हो जाएगा। Concurrency एक जटिल विषय है और कोई आसान जवाब नहीं है। मेरी प्राथमिकता अभिनेता पैटर्न का उपयोग करना और थ्रेड के बीच जितना संभव हो उतना छोटा डेटा साझा करना है। आदर्श, कोई नहीं। एक धागा प्रदर्शन कोड बहुत कुशलता से आमतौर पर पर्याप्त से अधिक है। –

उत्तर

24

दो बातें:

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

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

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

स्रोत: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

+0

vulkanino, तो अगर मैं एक ही विधि तक पहुंचने वाले थ्रेड का उपयोग करता हूं, तो हर बार सिंक्रनाइज़ किए जाने का बुद्धिमान विचार होगा। – 911TurboS

+0

+1, मेरा से बेहतर जवाब ... – Nim

+0

@ 911 टर्बो बस कुछ विधियों पर 'सिंक्रनाइज़' का उपयोग करके बहुप्रचारित कोड को सही तरीके से सिंक्रनाइज़ करने के लिए बेहद अपर्याप्त है। आपको डेटा स्थिरता (और शायद कई अन्य चीजों) से अवगत होना चाहिए। – toto2

11

Vulkanino अपने मुख्य प्रश्न के लिए एक अच्छा जवाब दिया, तो मैं केवल अपने प्रश्न के बारे में 3 के बाद मुद्रण 7.

3 7 के बाद मुद्रित कर सकते हैं को संबोधित करेंगे वास्तव में न होने के कारण जावा कोड की तुलना में आपके बयान में बहुत अधिक बाइट कोड।

मैं उस पर विस्तार करूंगा।

आप

System.out.println("Current Counter is: " + i); 

फोन और यह जावा कोड की एक पंक्ति में होता है, लेकिन वास्तव में क्या होता है एक स्ट्रिंग बनाई गई है और इसके बाद उस स्ट्रिंग println में भेजा जाता है है। वास्तव में कंसोल की रेखा लिखने से पहले println विधि को कुछ प्रोसेसिंग करना पड़ता है।

संकल्पनात्मक रूप से, कुछ ऐसा हो रहा है।

String printlnString = "Current Counter is: 3" 
--> maybe the other thread executes here 
System.out.println(printlnString); 
--> or maybe the other thread executes here 
i is now equal to 7 and the console has "Current Counter is: 7" 
println writes "Current Counter is: 3" to console 
+0

काउंटर को लिखने के बजाय, इसे एक साधारण सरणी में लिखें, फिर जब थ्रेड समाप्त हो जाए, तो सरणी मुद्रित करें। – cognacc