2012-01-05 4 views
5

मैं एक मान बदलता हूं जो निर्धारित करने के लिए प्रयोग किया जाता है कि थोड़ी देर के दौरान एक अलग-अलग लूप समाप्त हो जाता है।
मैं नहीं जानना चाहता कि यह काम कैसे प्राप्त करें। मैं केवल सिंक्रनाइज़ getters/setters यह काम करता है के रूप में उम्मीद के माध्यम से चर परीक्षण का उपयोग करते हैं ..एक मल्टीथ्रेडिंग प्रोग्राम में अनसंक्रोनिज्ड एक्सेस के साथ जावा में अजीब व्यवहार

मैं अपेक्षा की होगी, अगर कुछ पढ़ने/लिखने आदेशों संगामिति कार्यक्रम कभी कभी समाप्त नहीं करता की वजह से खो रहे हैं, लेकिन यह कभी नहीं कर देता है। क्या मुझे भ्रमित करता है ..
मैं जानना चाहता हूं कि कार्यक्रम कभी भी प्रिंट-कमांड के बिना समाप्त नहीं होता है। और मैं समझने के लिए क्यों प्रिंट कमांड कुछ भी बदल जाता है चाहते हैं ..

 

    public class CustomComboBoxDemo { 
     public static boolean test = true; 
     public static void main(String[] args) { 
      Thread user =new Thread(){ 
       @Override 
       public void run(){ 
        try { 
         sleep(2000); 
        } catch (InterruptedException e) {} 
        test=false; 
       } 
      }; 
      user.start(); 
      while(test) { 
       System.out.println("foo"); //Without this line the program does not terminate.. 
      } 
     } 
    } 

+0

देखें: [लूप को प्रिंट स्टेटमेंट के बिना परिवर्तित मूल्य दिखाई नहीं देता है] (https://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement) – Boann

उत्तर

8

सबसे अधिक संभावना स्पष्टीकरण यह है कि परिवर्तनीय केवल एक बार पढ़ता है, while को एक अनंत लूप (या नो-ऑप) में बदल देता है। चूंकि आपने test को volatile के रूप में घोषित नहीं किया है, इसलिए संकलक को ऐसा अनुकूलन करने की अनुमति है।

एक बार जब आप लूप के भीतर से बाहरी फ़ंक्शन को कॉल करते हैं, तो संकलक अब साबित नहीं कर सकता कि test लूप पुनरावृत्तियों में परिवर्तनीय बना हुआ है, और अनुकूलन नहीं करता है।

+1

मुझे आश्चर्य है, क्या यह बाइटकोड कंपाइलर या जेआईटी कंपाइलर है जो उस तरह का अनुकूलन करता है? – bezmax

+0

@ मैक्स: मेरे सिस्टम पर बाइटकोड कंपाइलर ऐसा नहीं करता है, इसलिए इसे जेआईटी कंपाइलर होना चाहिए। – NPE

+1

बीटीडब्ल्यू, यह भी हो सकता है कि यह लगातार इसे पढ़ रहा है, लेकिन कैश से ऐसा करना (एक सीपीयू रजिस्टर की तरह) जो मुख्य स्मृति को लिखने से प्रभावित नहीं होता है। फ़ील्ड को 'अस्थिर' के रूप में चिह्नित करने से यह भी ठीक हो जाएगा। – yshavit

0

मुझे लगता है यह तरीका आईओ नियंत्रित किया जाता है के साथ क्या करने के लिए कुछ है। प्रिंट के बिना, आप शायद सभी उपलब्ध CPU समय का उपयोग कर जावा एप्लिकेशन देखेंगे; प्रिंट के साथ यह संभावना है कि आईओ देरी अन्य प्रसंस्करण के लिए पर्याप्त CPU समय छोड़ दे।

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

जिसके अनुसार, यह JDK के तहत मेरे कार्य केंद्र पर ठीक समाप्त करने के लिए प्रकट होता है 1.6.0_10_b23

+0

Mcfinnigan के साथ सहमत हैं। अपने धागे में कुछ डिबगिंग प्रिंट जोड़ें। जब कुछ उम्मीद के अनुसार काम नहीं करता है, तो हमेशा यह साबित करने के लिए कुछ काम करें कि आपकी धारणाएं सही हैं, इस मामले में अलग थ्रेड डिज़ाइन के रूप में काम कर रहा है। – Mitch

1

test चर volatile के रूप में परिभाषित नहीं है, तो संकलक शायद अपने मुख्य लिए एक while(true) लूप में कोई आपरेशन युक्त पाश का अनुकूलन धागा और कार्यक्रम कभी खत्म नहीं होता है।

अन्यथा, test वैरिएबल का मान वास्तव में चेक किया गया है और जब आपका दूसरा धागा अपना मान बदलता है, तो मुख्य धागा while पाश छोड़ देता है और आपका प्रोग्राम समाप्त हो जाता है।

0

ऐसा लगता है कि आपके लूप को व्यस्त-प्रतीक्षा में गलत तरीके से संकलित किया जा रहा है। आपके बुलियन में एक अस्थिर कीवर्ड जोड़ना 'समस्या' को ठीक करता है।

0
public static boolean test = true; 
public static void main(String[] args) { 
    Thread user =new Thread(){ 
     @Override 
     public void run(){ 
      try { 
       sleep(2000); 
      } catch (InterruptedException e) {} 
      test=false; 
      System.out.println("Thread.end <"+test+">"); 
     } 
    }; 
    user.start(); 
    while(test); 
} 

यह दिलचस्प है। कंपाइलर शायद अंतहीन लूप में इसे अनुकूलित करता है, प्रत्येक लूप पर मान नहीं पढ़ता है।

volatile फिक्स इस रूप में परीक्षण को परिभाषित करने और अपने कार्यक्रम समाप्त

Btw करते हैं: आप शायद पहले से ही पता है कि तुम user.join) का उपयोग shoud (

0

समाप्त करने के लिए मुझे समझ नहीं आता थ्रेड के लिए प्रतीक्षा करने जो कोड आप जानते हैं उसका उपयोग करके आप जो करने की कोशिश कर रहे हैं वह सही ढंग से सिंक्रनाइज़ नहीं है।

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

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