2015-05-27 17 views
5

इस कोड को चलाना, मैं उम्मीद करता हूं कि यह परीक्षण चर को 5 सेकंड के लिए बढ़ाएगा और फिर समाप्त होगा।लूप समाप्त नहीं होने पर

import java.util.Timer; 
import java.util.TimerTask; 

public class Test { 
    private static boolean running; 

    public static void main(String[] args) { 
     long time = 5 * 1000;  // converts time to milliseconds 
     long test = Long.MIN_VALUE; 
     running = true; 

     // Uses an anonymous class to set the running variable to false 
     Timer timer = new Timer(); 
     timer.schedule(new TimerTask() { 
      @Override 
      public void run() { running = false; } 
     }, time); 

     while(running) { 
      test++; 
     } 

     timer.cancel(); 
     System.out.println(test); 
    } 
} 

लेकिन जब मैं इसे चलाने के कार्यक्रम खत्म नहीं होता (मुझे लगता है, मैं इसे समय के लिए उचित समय दे दिया है)। लेकिन अगर मैं

while(running) { 
     System.out.println(); 
     test++; 
    } 

जबकि पाश बदलने कार्यक्रम समय की उम्मीद राशि में खत्म (और लाइनों का एक बहुत बाहर प्रिंट)। मुझे समझ में नहीं आता यह व्यवहार क्यों होता है?

+0

यदि आप 'अस्थिर' चलाना चाहते हैं तो क्या होगा? –

+0

मैंने इंटेलिजे 11 के साथ जेडीके 7 का उपयोग करके अपने कोड का परीक्षण किया और दोनों संस्करण कुछ सेकंड में समाप्त हो गए। आप दौड़ने के लिए क्या उपयोग कर रहे हैं? –

+0

@ एंडी टर्नर वाह, मैं पहले कभी अस्थिर कीवर्ड में नहीं आया हूं। Thats कोड काम करता है। धन्यवाद! – DenverCoder9

उत्तर

4

Java Memory Model के अनुसार कोई गारंटी नहीं है जब गैर-अस्थिर क्षेत्र किसी अन्य धागे से दिखाई देगा। आपके मामले में आपकी मुख्य विधि जेआईटी संकलित है और जेआईटी-कंपाइलर उचित रूप से मानते हैं कि वर्तमान थ्रेड running एक लूप में चर को संशोधित नहीं करता है, तो हमें इसे प्रत्येक पुनरावृत्ति पर पढ़ने को परेशान नहीं करना चाहिए और लूप को अनंत तक परिवर्तित करना चाहिए। इस मामले के बारे में FindBugs warning भी है।

जब आप एक System.out.println कॉल जोड़ने के लिए, लगता है कि JIT कम्पाइलर यह अनुरूप नहीं कर सकते हैं, तो यह सुनिश्चित करें कि इस विधि running चर संशोधित नहीं करता है नहीं हो सकता है इस प्रकार यह क्षेत्र पढ़ने अनुकूलन बंद स्विच करता है। हालांकि इसे समस्या समाधान के रूप में नहीं माना जाना चाहिए: यह संभव है कि जावा के नए संस्करण बेहतर हों और आपके लूप को अनुकूलित करें भले ही आपके पास System.out.println है।

+0

मैंने यह उत्तर स्वीकार कर लिया क्योंकि यह अतिरिक्त जानकारी को लिंक करता है। धन्यवाद! – DenverCoder9

2

अपने कोड में करीब चलें ...

आप अपने कोड डीबग करते हैं, यह काम करेंगे। ऐसा इसलिए है क्योंकि आप केवल एक धागा और कोई कैश नहीं देखेंगे। जावा थ्रेड-आधारित कैश तंत्र का उपयोग कर सकते हैं। आपको इसे मुख्य स्मृति में पढ़ने और लिखने की आवश्यकता है।

तो यदि आप अपने चल रहे चर पर volatile कीवर्ड का उपयोग करते हैं, तो jvm इसे एकाधिक धागे द्वारा संपादन योग्य के रूप में देखेगा, और इसे कैश नहीं किया जाना चाहिए।

इसलिए आपकी स्थिति में समाधान आपके चल रहे चर में volatile जोड़ रहा है।

2

आप अपने main विधि से एक अलग थ्रेड में running चर अद्यतन कर रहे हैं। जावा मेमोरी मॉडल ऐसा है कि आपको विभिन्न धागे में गैर-अस्थिर चर के अपडेट देखने की गारंटी नहीं है।

सबसे आसान समाधान वैरिएबल volatile बनाने के लिए है: यह थ्रेड को एक्सेस करने पर चर के 'वर्तमान' मान को चेक करने के लिए मजबूर करता है।

अन्य समाधान boolean के बजाय AtomicBoolean का उपयोग कर, और पारस्परिक रूप से synchronized ब्लॉक (अर्थात कोड कि running तक पहुँचता कोड है जो इसे अद्यतन करता है के रूप में ही मॉनीटर पर सिंक्रनाइज़ है) में running के लिए उपयोग लपेटकर शामिल हैं।

मैं दृढ़ता से अनुशंसा करता हूं कि आप जावा कंसुरेंसी इन प्रैक्टिस की एक प्रति चुनें, जो इस समस्या का विस्तार से वर्णन करता है।

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