2016-01-07 12 views
5

के कारण चलने वाले थ्रेड में देरी निम्न कोड में, यदि मैं लूप के अंदर सिसआउट कथन का उपयोग करता हूं तो कोड निष्पादित होने के बाद लूप के अंदर निष्पादित करता है और चला जाता है लेकिन अगर मैं अंदर sysout कथन का उपयोग नहीं करता लूप तब तत्काल लूप चला जाता है अगर स्थिति में अंदर प्रवेश किए बिना भी भले ही अगर स्थिति संतुष्ट हो .. क्या कोई भी कृपया इसके लिए सही कारण जानने में मेरी मदद कर सकता है। बस एक sysout कथन अगर शर्त सच बनने के लिए बनाते हैं। ऐसा क्यों है?system.out.println कथन

class RunnableDemo implements Runnable { 
    private Thread t; 
    private String threadName; 

    RunnableDemo(String name){ 
     threadName = name; 
     System.out.println("Creating " + threadName); 
    } 
    public void run() { 
     System.out.println("Running " + threadName); 
     for(;;) 
     { 
      //Output 1: without this sysout statement. 
      //Output 2: After uncommenting this sysout statement 
      //System.out.println(Thread.currentThread().isInterrupted()); 
      if(TestThread.i>3) 
      { 
       try { 
        for(int j = 4; j > 0; j--) { 
         System.out.println("Thread: " + threadName + ", " + j); 
        } 
       } catch (Exception e) { 
        System.out.println("Thread " + threadName + " interrupted."); 
       } 
       System.out.println("Thread " + threadName + " exiting."); 
      } 
     } 
    } 

    public void start() 
    { 
     System.out.println("Starting " + threadName); 
     if (t == null) 
     { 
     t = new Thread (this, threadName); 
     t.start(); 
     } 

    } 

} 

public class TestThread { 
     static int i=0; 
    public static void main(String args[]) { 

     RunnableDemo R1 = new RunnableDemo("Thread-1"); 
     R1.start(); 
     try { 
     Thread.sleep(10000); 
    } catch (InterruptedException e) { 

     e.printStackTrace(); 
    } 

    i+=4; 
    System.out.println(i); 
    } 
} 

अनंत लूप में sysout बयान बिना आउटपुट: - -: अनंत लूप में sysout बयान के साथ enter image description here

आउटपुट: - enter image description here

कोड के रूप में इस प्रकार है

+2

इम वाला लगता है कि आप अस्थिर मुद्दों में चल रहे हैं। स्थिर int i = 0 बनाने का प्रयास करें; स्थैतिक अस्थिर int i = 0; यदि व्यवहार अब एक ही बीमार है तो एक स्पष्टीकरण के साथ एक जवाब डाल दिया। –

+0

@Aaron यह एक अनंत लूप है, इसलिए वे इसे लगातार निष्पादित करते रहते हैं, है ना? संपादित करें: हारून ने इमारत छोड़ दी। –

+1

@ हेनक डी बोयर, मैंने अस्थिरता का उपयोग करने की कोशिश की और यह ठीक काम कर रहा है। लेकिन क्या आप समझा सकते हैं कि sysout कथन कौन से परिवर्तन करता है जो कोड को अस्थिर कीवर्ड का उपयोग किये बिना भी काम करने देता है। –

उत्तर

3

समस्या यहाँ

static volatile int i=0;

एक चर volatile बनाने के लिए

static int i=0;

बदलकर ठीक किया जा सकता जटिल परिणामों की एक संख्या है और मैं इस पर एक विशेषज्ञ नहीं हूँ। तो, मैं यह बताने की कोशिश करूंगा कि मैं इसके बारे में कैसे सोचता हूं।

परिवर्तनीय i आपकी मुख्य मेमोरी, आपकी रैम में रहता है। लेकिन राम धीमा है, इसलिए आपका प्रोसेसर इसे तेज (और छोटी) स्मृति में कॉपी करता है: कैश। वास्तव में कई कैश, लेकिन यह अप्रासंगिक है।

लेकिन जब दो अलग अलग प्रोसेसर पर दो धागे अलग कैश में उनके मान रखा है, क्या होता है जब मूल्य परिवर्तन? खैर, अगर धागा 1 कैश 1 में मूल्य परिवर्तन, धागा 2 अभी भी कैश 2. से पुराने मान का उपयोग करता जब तक हम दोनों धागे कि इस परिवर्तनीय i किसी भी समय बदल रहा है हो सकता है, जैसे कि वह जादू थे बताओ। अस्थिर कीवर्ड यही करता है।

तो क्यों यह प्रिंट बयान के साथ काम करता है? खैर, प्रिंट स्टेटमेंट दृश्यों के पीछे बहुत सारे कोड का आह्वान करता है। इस कोड के कुछ सबसे अधिक संभावना एक तुल्यकालन ब्लॉक या किसी अन्य अस्थिर चर, जो (दुर्घटना से) भी दोनों कैश में i का मूल्य ताज़ा करता है शामिल हैं। (इस बिंदु को इंगित करने के लिए मार्को 13 के लिए धन्यवाद)।

अगली बार जब आप i तक पहुँचने का प्रयास है, तो आप अद्यतन मूल्य प्राप्त करें!

पुनश्च: मैं यहाँ राम कह रहा हूं, लेकिन शायद दो धागे, जो एक कैश अगर वे उदाहरण के लिए hyperthreaded कर रहे हैं हो सकता है के बीच करीबी साझा स्मृति।

यह एक बढ़िया स्पष्टीकरण भी है (चित्रों के साथ!):

http://tutorials.jenkov.com/java-concurrency/volatile.html

+0

एक और बात मैं पूछना चाहता हूं, अगर मैं sysout कथन के बजाय thread.sleep का उपयोग करता हूं, तब भी अगर स्थिति सत्य हो जाती है। क्या Thread.sleep भी कुछ स्मृति लेता है और डेटा को कैश से दूर कर देता है? –

+0

@ मार्को 13 ठीक है, मैं जवाब को अनुकूलित करूंगा। सुधारों के लिए धन्यवाद! –

+0

@MeenakshiKumari पता लगाने का सबसे अच्छा तरीका यह है कि आप इसे जांच लें! :) लेकिन नहीं, मैं ऐसा नहीं सोचूंगा, जब तक (एक बार फिर दुर्घटना से) कोड का कुछ विदेशी टुकड़ा नींद चल रहा है, जबकि कैश स्पष्ट हो जाता है। जैसे मैंने कहा, मैं एक विशेषज्ञ नहीं हूं और प्रतीत होता है कि अभ्यास में थ्रेडिंग अक्सर अधिक जटिल होती है। इसलिए मुझे यहां बहुत ठोस नियम देने में संकोच नहीं है, क्षमा करें। नींद खुद ही ओएस को बता रही है कि अब आपके पास कुछ भी करने की ज़रूरत नहीं है, और कुछ नहीं, इसलिए आपको स्मृति पर फ्लश करने जैसी कोई विशेष संपत्ति रखने पर भरोसा नहीं करना चाहिए। –

2

जब आप एक चर मूल्य का उपयोग कर रहे हैं, तो चा nges वास्तविक स्मृति स्थान हर बार (या लोड) से नहीं लिखा जाता है। मूल्य को सीपीयू रजिस्टर में लोड किया जा सकता है, या कैश किया जा सकता है, और कैश फ्लेश होने तक वहां बैठे। इसके अलावा, क्योंकि TestThread.i लूप के अंदर संशोधित नहीं किया गया है, तो ऑप्टिमाइज़र इसे लूप से पहले चेक के साथ प्रतिस्थापित करने का निर्णय ले सकता है, और if कथन से पूरी तरह से छुटकारा पा सकता है (मुझे नहीं लगता कि यह वास्तव में आपके मामले में हो रहा है, लेकिन मुद्दा यह है कि यह हो सकता है)।

अनुदेश कि अपनी कैश फ्लश और उन्हें भौतिक स्मृति की मौजूदा सामग्री के साथ सिंक्रनाइज़ करने के लिए धागा बनाता स्मृति बाधा कहा जाता है। मेमोरी बाधा को मजबूर करने के लिए जावा में दो तरीके हैं: synchronized ब्लॉक दर्ज करें या बाहर निकलें या volatile चर का उपयोग करें। जब इनमें से कोई भी घटना होती है, तो कैश फ़्लश हो जाते हैं, और थ्रेड को स्मृति सामग्री के अप-टू-डेट दृश्य को देखने की गारंटी दी जाती है, और इसमें सभी बदलावों को स्थानीय रूप से स्मृति के लिए प्रतिबद्ध किया गया है।

तो, के रूप में टिप्पणी में सुझाव दिया, volatile के रूप में अपने घोषणा TestThread.i हैं, समस्या दूर जाना होगा, क्योंकि जब भी मूल्य संशोधित किया गया है, परिवर्तन तुरंत प्रतिबद्ध किया जाएगा, और अनुकूलक अनुकूलक के लिए नहीं पता चल जाएगा, ई की जांच लूप से दूर, और मूल्य कैश नहीं करने के लिए।

अब, प्रिंट स्टेटमेंट जोड़ने से व्यवहार में परिवर्तन क्यों होता है? खैर, आईओ के अंदर बहुत सी सिंक्रनाइज़ेशन चल रहा है, थ्रेड कहीं मेमोरी बाधा हिट करता है, और ताजा मान लोड करता है। यह सिर्फ एक संयोग है।

+0

मैं यह नहीं कह रहा कि आप गलत हैं, लेकिन क्या अनुकूलक को सदस्य चर के बारे में ऐसी भारी धारणाएं करने की अनुमति है? त्रुटि प्रवण लगता है। –

+0

ज़रूर, क्यों नहीं? यदि लूप के अंदर कोई मेमोरी बाधा नहीं है, और एक चर को वर्तमान थ्रेड द्वारा संशोधित नहीं किया गया है, तो यह मानना ​​पूरी तरह से सुरक्षित है कि यह स्थिर रहता है। वास्तव में, यह धारणा इसे बनाने से सुरक्षित नहीं है, क्योंकि यह व्यवहार निर्धारक बनाता है। – Dima

+0

हाँ, लेकिन यह संकलन समय पर कैसे पता चलता है कि थ्रेड से पहले मैं का मूल्य बदल नहीं पाऊंगा? शायद मैं कुछ याद कर रहा हूँ। –

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