2016-09-28 24 views
5

यहाँ मेरी कोड है:सिंक्रनाइज़ क्यों ठीक से काम नहीं कर रहा है?

private int count = 0; 

    public synchronized void increment() { 
     count++; 
    } 

public void doWork() throws InterruptedException { 

    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       increment(); 
       System.out.println(count+" "+Thread.currentThread().getName()); 
      }}}); 

    Thread t2 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       increment(); 
       System.out.println(count+" "+Thread.currentThread().getName()); 
      }}}); 

    t1.start(); 
    t2.start(); 
} 

यहाँ मेरी उत्पादन है:

2 Thread-1 
2 Thread-0 
3 Thread-1 
5 Thread-1 
6 Thread-1 
4 Thread-0 
8 Thread-0 
9 Thread-0 
7 Thread-1 
10 Thread-0 

मेरे समझ के साथ कि incrementsynchronized है। तो, इसे पहले increment एक नंबर होना चाहिए और फिर lock जारी करें और फिर lock को t1 या t2 पर lock दें। तो, यह एक समय में increment एक नंबर होना चाहिए, है ना?

लेकिन मेरा कोड incrementing एक समय में दो या तीन नंबर क्यों है? क्या मैं कुछ गलत कर रहा हूं (मैं नौसिखिया हूँ)?

+9

'वृद्धि '' सिंक्रनाइज़' है, लेकिन 'गिनती' नहीं है। दो बयान 'वृद्धि() 'और' System.out.println() 'परमाणु नहीं हैं। – bradimus

उत्तर

5

जबकि count++; वास्तव में System.out.println(count+" "+Thread.currentThread().getName()); सिंक्रनाइज़ किया गया है, लेकिन यह count चर तक पहुंच है। आप का उपयोग सिंक्रनाइज़

यहां तक ​​कि अगर, यह आप में मदद नहीं करेगा क्योंकि अगले परिदृश्य अभी भी संभव हो जाएगा:

  • थ्रेड 1 वेतन वृद्धि
  • थ्रेड 2 वेतन वृद्धि
  • थ्रेड 1 प्रिंट मूल्य 2
  • थ्रेड 2 प्रिंट वैल्यू 2

इस समस्या को ठीक करने के लिए आपको समान सिंक्रनाइज़ अनुभाग में वृद्धि और प्रिंट करें। उदाहरण के लिए आप System.out.println(count+" "+Thread.currentThread().getName());increment विधि में डाल सकते हैं।

+1

या 'गिनती' अस्थिर बनाओ। – chrylis

+0

धन्यवाद, यह काम किया। चियर्स! –

+0

@chrylis यह पहली समस्या हल करेगा, लेकिन दूसरा नहीं। – talex

0

वास्तव में क्या होता है यह है कि आपके थ्रेड स्नैपशॉटिंग (शायद एक और शब्द बेहतर है) वर्तमान वैरिएबल count के मान और इसे प्रदर्शित करें। आप इसके बारे में सोच सकते हैं जैसे शून्य शून्य के साथ एक नीली बाल्टी है और Threads दोनों एक ही रंग और संख्या में एक ही बाल्टी प्राप्त कर रहे हैं। वे अब उन बाल्टी पर व्यक्तिगत रूप से काम करते हैं।

यदि आप उन्हें एक ही बाल्टी पर काम करना चाहते हैं, तो आपको उन्हें परमाणु बनाना होगा। AtomicInteger या volatile या जावा समवर्ती पैकेज से कोई अन्य टूल के साथ।

1

increment विधि increment विधि रिटर्न के बाद अन्य धागे पर चलाया जा सकता है, लेकिन count से पहले संयोजन

count+" "+Thread.currentThread().getName() 

आप जैसे सकता है के लिए लिया गया है

public synchronized int incrementAndGet() { 
    count++; 
    return count; // read access synchronized 
} 
for (int i = 0; i < 5; i++) { 
    System.out.println(incrementAndGet()+" "+Thread.currentThread().getName()); 
} 

या the class in the standard library specifically designed for this purpose का उपयोग करें::

private final AtomicInteger counter = new AtomicInteger(0); 

public void doWork() throws InterruptedException { 

    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       System.out.println(counter.incrementAndGet() + " " + Thread.currentThread().getName()); 
      } 
     } 
    }); 

    Thread t2 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       System.out.println(counter.incrementAndGet() + " " + Thread.currentThread().getName()); 
      } 
     } 
    }); 

    t1.start(); 
    t2.start(); 
} 

बेशक यह जरूरी संख्या 1 से 10 में मुद्रित किया जा रहा नेतृत्व नहीं करता है को संशोधित करने और एक सिंक्रनाइज़ ब्लॉक में count पुन: प्राप्त करने से इसे ठीक आदेश, बस एक बार से अधिक संख्या में पुनर्प्राप्त नहीं किया गया है।निम्नलिखित उत्पादन हो सकता है:

2 Thread-0 
3 Thread-0 
4 Thread-0 
1 Thread-1 
5 Thread-0 
6 Thread-1 
7 Thread-0 
8 Thread-1 
9 Thread-1 
10 Thread-1 
+0

मैंने दोनों की कोशिश की लेकिन यह काम नहीं करता है। –

+0

@ हेमलाटा ओह, यह काम करता है, लेकिन आप स्पष्ट रूप से ऐसा किए बिना प्रिंट स्टेटमेंट को सिंक्रनाइज़ करने की उम्मीद नहीं कर सकते हैं, और आपने इस सवाल में ऐसे प्रतिबंध का उल्लेख नहीं किया है। (कोई संख्या एक से अधिक बार नहीं होती है, कोई संख्या गुम नहीं होती है, संख्याएं प्रत्येक थ्रेड पर आरोही क्रम में मुद्रित होती हैं।) इसके अलावा उस परिदृश्य में एकाधिक धागे का उपयोग करने से कोई अर्थ नहीं होता है ... – fabian

+0

शायद मैं कुछ गलत कर रहा हूं यह काम नहीं कर रहा है, क्योंकि मैं एक नौसिखिया हूँ। –

0

समाधान 1: फैबियन से देखते हुए। एक समारोह को incrementAndGet() देने के लिए।

समाधान 2: एक synchronized ब्लॉक के बजाय synchronized विधि (यदि संभव हो तो): synchronized का उपयोग किए बिना

private int count = 0; 
private Object dummyObject = new Object(); 

public void increment() { 
    count++; 
} 

public int getCount() { 
    return count; 
} 

public void doWork() throws InterruptedException { 

    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       synchronized (dummyObject) { 
        increment(); 
        System.out.println(count + " " + Thread.currentThread().getName()); 
       } 
      } 
     } 
    }); 

    Thread t2 = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 0; i < 5; i++) { 
       synchronized (dummyObject) { 
        increment(); 
        System.out.println(count + " " + Thread.currentThread().getName()); 
       } 
      } 
     } 
    }); 

    t1.start(); 
    t2.start(); 
} 
+0

इससे मदद नहीं मिलती है क्योंकि 'वृद्धि' के कॉल और 'getCount' की कॉल के बीच मूल्य अभी भी बदला जा सकता है, क्योंकि उस मामले में मॉनिटर को दो बार एक्वायर किया जाता है। – fabian

0

एक वैकल्पिक समाधान:

पूरा कोड जैसा होगा।

के बाद से आपके उपयोग के मामले सरल है (बस काउंटर incrimenting और मूल्य प्रिंट, AtomicInteger बेहतर विकल्प है

import java.util.concurrent.atomic.AtomicInteger; 

public class TestCounter{ 
    private AtomicInteger count = new AtomicInteger(0); 

    public void doWork() throws InterruptedException { 

     Thread t1 = new Thread(new Runnable() { 
      public void run() { 
       for (int i = 0; i < 5; i++) { 
        System.out.println(""+Thread.currentThread().getName()+":"+count.incrementAndGet()); 
       }}}); 

     Thread t2 = new Thread(new Runnable() { 
      public void run() { 
       for (int i = 0; i < 5; i++) { 
        System.out.println(""+Thread.currentThread().getName()+":"+count.incrementAndGet()); 
       }}}); 

     t1.start(); 
     t2.start(); 
    } 

    public static void main(String args[]) throws Exception{ 
     TestCounter tc = new TestCounter(); 
     tc.doWork(); 
    } 
} 

उत्पादन:। यही कारण है कि इन नंबरों

Thread-0:1 
Thread-0:3 
Thread-0:4 
Thread-0:5 
Thread-0:6 
Thread-1:2 
Thread-1:7 
Thread-1:8 
Thread-1:9 
Thread-1:10 

@fabian जवाब का संदर्भ लें के लिए अनुक्रम में मुद्रित नहीं हैं और न ही

यदि आप 1-10 से आरोही क्रम में संख्याओं की श्रृंखला में अनुक्रम की अपेक्षा करते हैं, तो थ्रेड की आवश्यकता नहीं है।

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