2012-01-10 14 views
6

मेरे पास एक थ्रेड क्लास है जो इंस्टेंस वैरिएबल के रूप में चलने योग्य और int काउंटर लागू करती है। दो सिंक्रनाइज़ किए गए विधियां जोड़ें और उप। जब मैं अपनी टेस्ट क्लास चलाता हूं तो किसी भी समय यह गलत परिणामों को दो बार प्रिंट कर रहा है। जहां तक ​​मैं समझता हूं कि जब कोई विधि सिंक्रनाइज़ होती है, तो संपूर्ण ऑब्जेक्ट को अन्य थ्रेडों तक पहुंचने के लिए लॉक कर दिया जाएगा, इस तर्क के साथ हर बार हमें एक ही परिणाम मिलना चाहिए? कुछ कैसे मामला नहीं है। क्या मैं कुछ भूल रहा हूँ?जावा थ्रेड के साथ असंगत परिणाम

मेरी मशीन विंडोज 7, 64 बिट है।

public class ThreadClass implements Runnable { 

     int counter = 0; 

     @Override 
     public void run() { 
      add(); 
      sub(); 
     } 

     public synchronized void add() { 
      System.out.println("ADD counter" + (counter = counter + 1)); 
     } 

     public synchronized void sub() { 
      System.out.println("SUB counter" + (counter = counter - 1)); 
     } 
    } 

Testclass

public class ThreadTest { 

    public static void main(String args[]) { 
     ThreadClass tc = new ThreadClass(); 
     Thread tc0 = new Thread(tc); 
     tc0.start(); 
     tc0.setPriority(Thread.MAX_PRIORITY); 
     Thread tc1 = new Thread(tc); 
     tc1.start(); 
     tc1.setPriority(Thread.NORM_PRIORITY); 
     Thread tc2 = new Thread(tc); 
     tc2.start(); 
     tc2.setPriority(Thread.MIN_PRIORITY); 
    } 
} 

परिणाम

ADD counter1 
ADD counter2 
SUB counter1 
SUB counter0 
ADD counter1 
SUB counter0 

नोट: आप रन की जोड़ी करने के लिए इस विसंगति का उत्पादन करने की आवश्यकता हो सकती।

+2

आपको 'एडीडी विधि' में प्रिंटलाइन को 'एडीडी काउंटर' में बदलना चाहिए ताकि यह देखना आसान हो कि क्या हो रहा है और शायद प्रत्येक थ्रेड के लिए भी प्रदान और आईडी भी हो ताकि आप देख सकें कि कौन सा आउटपुट थ्रेड से आता है। – ChrisWue

+0

@ChrisWue। मैं फिर से अद्यतन System.out के साथ भाग गया। पॉइंटिंग के लिए धन्यवाद। – kosa

उत्तर

3

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

हालांकि, यह धागे के क्रम के बारे में कुछ और नहीं दर्शाता है। आप तीन धागे शुरू कर रहे हैं - एकमात्र गारंटी यह है कि वे add या sub विधियों को एक साथ चलाकर एक-दूसरे पर चिपक नहीं पाएंगे। थ्रेड 1 add() पर कॉल कर सकता है, फिर थ्रेड 3 add() पर कॉल कर सकता है, फिर थ्रेड 2 add() पर कॉल कर सकता है, फिर वे सभी sub() पर कॉल कर सकते हैं। या वे सभी add() और फिर sub() प्रत्येक कॉल कर सकते हैं।या कोई मिश्रण - एकमात्र आवश्यकता यह है कि प्रत्येक थ्रेड add() को sub() पर कॉल करने से पहले कॉल करता है और यह कि कोई भी दो धागे कभी भी add() या sub() पर कॉल नहीं करेंगे जबकि एक अन्य थ्रेड उस विधि में है।

एक तरफ: यह हो सकता है, कुछ मामलों में, बुरा रूप this पर सिंक्रनाइज़ करने के लिए, यह सार्वजनिक हो के रूप में - यह अक्सर पर लॉक करने के लिए एक आंतरिक निजी Object उपयोग करने के लिए इतना है कि कोई अन्य कॉल अपने लॉक ले जा सकते हैं को प्राथमिकता दी है और किसी भी ताला का उल्लंघन रणनीतियों को आपने डिजाइन किया है।

+0

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

+1

@ थिंकस्टीप: यदि आप प्रत्येक थ्रेड को दूसरे के लिए इंतजार करना चाहते हैं तो आप धागे का उपयोग क्यों कर रहे हैं एक शुरू करने से पहले समाप्त हो जाएगा? आप एक ही थ्रेड में निष्पादित किए जा सकने वाले संचालन का अनुक्रम समाप्त कर सकते हैं। –

+0

@ थिंकस्टीप: हाँ, निजी लॉक आपको वास्तव में एक ही परिणाम देगा। यह एक कोड शैली मुद्दा है जिसे आप चाहें बग नहीं, आदत में आने के लिए। वैसे भी, प्राथमिकताएं ** संकेत ** हैं, गारंटी नहीं। अगर आपको एक विशेष आदेश सुनिश्चित करने की आवश्यकता है, तो आपको अपना शेड्यूलिंग संभालना होगा। –

5

आपके परिणाम सही दिखते हैं।

विधियों के निष्पादन के दौरान, ऑब्जेक्ट पर एक विशेष लॉक प्राप्त किया जाता है, लेकिन add() और sub() कॉल के बीच, थ्रेड स्वतंत्र रूप से अंतःस्थापित हो सकते हैं।

यदि आप सभी धागे चलाने के बाद कुल 0 के साथ समाप्त होते हैं, तो उनमें से कोई भी ईथोर को ओवरराइट नहीं करता है और counter तक पहुंच सिंक्रनाइज़ किया गया था।

आप counter नहीं रखना चाहती हैं केवल 0 से 1 क्रमिक रूप से करने के लिए और हिट 2 कभी नहीं जाना है, तो निम्न कार्य (विधि-स्तरीय तुल्यकालन इतने लंबे समय के रूप में कोई अन्य वर्गों शामिल कर रहे हैं निरर्थक प्रस्तुत करना देंगे):

@Override 
public void run() { 
    synchronize(this) { 
     add(); 
     sub(); 
    } 
} 

हालांकि, यह थ्रेड के पूरे बिंदु को बेकार बनाता है क्योंकि आप इसे एकल-थ्रेडेड लूप में कर सकते हैं।

+0

मैं कुल 0 कथन के साथ समाप्त होने के साथ सहमत हूं, लेकिन अगर मैं सिंक्रनाइज़ेशन को सही ढंग से समझता हूं, तो मुझे 2 नहीं मिलना चाहिए, क्योंकि ऐड/सब उसी थ्रेड में हैं जो ऑब्जेक्ट को शुरुआत के लिए लॉक करता है। यदि नहीं, तो सिंक्रनाइज़ किए गए कीवर्ड के वास्तविक उपयोग का क्या उपयोग है? आप देखते हैं कि मैं समझने के लिए क्या संघर्ष कर रहा हूं? – kosa

+0

जब 'रन()' विधि किसी थ्रेड पर निष्पादित हो रही है, तो उसके पास लॉक नहीं है ('run()' सिंक्रनाइज़ नहीं है)। जब यह 'add()' कॉल का सामना करता है, तो यह लॉक को पकड़ने का प्रयास करता है। यदि लॉक उपलब्ध नहीं है तो यह इंतजार कर रहा है। एक बार 'add()' कॉल समाप्त हो जाने पर, यह लॉक जारी करता है। इस बिंदु पर एक और धागा इसके लिए इंतजार कर रहा है और दूसरे थ्रेड के 'उप()' को निष्पादित करने का मौका देने से पहले ताला पकड़ लेता है। यही कारण है कि दो 'जोड़()' कॉल एक पंक्ति में हो सकती है। –

+0

हालांकि मैं आपकी व्याख्या के साथ सहमत हूं, यह समझाता नहीं है कि काउंटर 2 से 0 तक बिना कैसे जा सकता है। System.out.println क्यों लाइनों को पुन: व्यवस्थित करता है? –

2

परिणामों के सेट के साथ कुछ भी गलत नहीं है। वे आपके कोड के साथ पूरी तरह से संगत हैं। एकाधिक धागे के चल रहे क्रम की गारंटी नहीं है।

आपकी 'सिंक्रनाइज़' विधियां सुनिश्चित करती हैं कि आपको वैध परिणाम मिलते हैं - add पर प्रत्येक कॉल वास्तव में एक और प्रत्येक कॉल को sub पर वास्तव में घटा देता है। उनके बिना, आप शून्य के अलावा अंतिम परिणाम प्राप्त कर सकते हैं।

+0

आपके उत्तर – kosa

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