2012-12-09 19 views
5

मेरे पास (सत्य) लूप का अजीब व्यवहार है। यहाँ कोड है:लूप और कतार के साथ अजीब जावा व्यवहार

वर्ग के एक सदस्य के रूप में मेरे पास है:

static Queue<Object> response = new LinkedList<Object>(); 

... और एक समारोह:

private void read() { 

    while (true) 
    { 
     System.out.println("foo"); 
     if(!(response.isEmpty())) 
     { 

      if((Boolean)response.peek() == true) 
      { 
       view.dispose(); 
       LogInControler controler= new LogInControler(); 
       disableMasterLogin(); 
       response.poll(); 
       return; 
      } 
      else if((Boolean)response.poll() == false) 
      { 
       JOptionPane.showMessageDialog(view.getRootPane(), 
         "Wrong username or password."); 
       view.tfUsername.requestFocus(); 
       return; 
      } 
     } 
    } 
} 

वस्तु सर्वर से प्राप्त किया जाता है (सॉकेट) के माध्यम से, InputController वर्ग उस ऑब्जेक्ट को उपयुक्त नियंत्रक के पास पास करता है, इस मामले में MasterLogInController और इसे कतार प्रतिक्रिया में डाल दें। मैं (सत्य) पाश में उस प्रतिक्रिया का इंतजार कर रहा हूं, लेकिन समस्या यह है कि अगर मैं "System.out.printline (" foo ") को हटा देता हूं;" लूप केवल एक बार दर्ज किया जाएगा !? इस syso लाइन के साथ मैं "बल" जबकि लूप करने के लिए लूप करने के लिए प्रतिक्रिया प्राप्त होने तक। यहाँ क्या गलत है?

+0

तुम बस, जबकि पाश में सच कहें, कि तुम क्या सच हो गया है निर्दिष्ट करने के लिए की जरूरत है। – DrinkJavaCodeJava

+0

मेरे लिए, यह किसी प्रकार की दौड़ की स्थिति के रूप में लगता है। आप इसे शुरू करने वाले धागे में आमंत्रित करते हैं, है ना? इस विधि में सभी अपवादों को पकड़ने और उन्हें मुद्रित करने का प्रयास करें। –

+0

https://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement – Boann

उत्तर

4

मुझे लगता है कि आपके पास कई धागे चल रहे हैं।

System.out.println मेमोरी बाधा उत्पन्न करता है जो संभवतः आपके कोड को कुछ चर देखता है जो अन्यथा दिखाई नहीं दे रहा है (सिंक्रनाइज़ेशन की कमी के कारण)।

विशेष रूप से, आपकी कतार थ्रेड सुरक्षित नहीं है और इसे सुरक्षित रूप से प्रकाशित होने लगते हैं।

  • अपने while पाश अपनी हालत में response अशक्त ==> NullPointerException
  • reponse.isEmpty() झूठी वापस कर सकती है लेकिन response.peek() अशक्त वापस कर सकती है, जिसे फिर आप Boolean लिए डाली और Unbox के रूप में देख सकते हैं: इसलिए यह बहुत बोधगम्य है कि है if((Boolean)xxx == true) ==> NullPointerException
  • आदि

अलावा टिप्पणी में दिए गए ध्वनि सलाह से मदद करने के लिए कारण समझने के लिए, आप चाहिए कोड धागा सुरक्षित बनाओ। उदाहरण के लिए, आप thread safe BlockingQueue का उपयोग कर सकते हैं। लेकिन यह संभवतः पर्याप्त नहीं होगा (अगर आपके विभिन्न/अगर/यदि अन्य बयान दिए गए हैं और तथ्य यह है कि कतार प्रत्येक कथन के बीच किसी अन्य धागे द्वारा बदला जा सकता है)।

+0

धन्यवाद! यह सब कुछ बताता है। – Maleta

+0

केवल मुझे बदलना था कतार के बजाय मुझे ब्लॉकिंगक्यूयू प्रतिक्रिया = नया लिंक्डब्लॉकिंग क्यूयू (); लेकिन अभी भी अजीब बनी हुई है कि मुझे इसके साथ समस्या क्यों थी, और मेरे दोस्त ने मेरे कंप्यूटर पर नहीं किया (हमारे पास जावा का एक ही संस्करण है - 7u9)। – Maleta

+0

यह जेवीएम पैरामीटर (क्लाइंट या-सर्वर), प्रोसेसर आर्किटेक्चर, कोर की संख्या, ओएस (उदाहरण के लिए विंडोज बनाम लिनक्स), सीपीयू लोड सहित अन्य कारकों आदि पर कई कारकों पर निर्भर हो सकता है। तथ्य यह है कि यह काम करता है एक कंप्यूटर बस संयोग था और पर भरोसा नहीं किया जा सकता है। यदि आप प्रोग्राम को अपने मित्र के कंप्यूटर पर कई बार चलाते हैं तो यह कुछ चरण में टूट सकता है। – assylias

2

मुझे संदेह है कि क्या हो रहा है यह है कि आपके लूप को जेआईटी कंपाइलर द्वारा अस्तित्व से अनुकूलित किया जा रहा है। यदि response.isEmpty() पहली बार आपके लूप में कहा जाता है, और यह देखते हुए कि responsesynchronized ब्लॉक या विधि के अंदर नहीं है, या volatile चिह्नित है, तो संभव है कि जेआईटी कंपाइलर यह तय करेगा कि यह बदलने वाला नहीं है और केवल दिखाई देने वाला है कोड चलाने से खाली व्यस्त पाश होने के लिए।

println() कथन में जोड़ना कम से कम लूप को जेआईटी कंपाइलर की आंखों में एक उद्देश्य देता है, इसलिए यह उस मामले में इसे छोड़ देगा।

इसे ठीक करने के assylias द्वारा दिए गए मुख्य सलाह के अलावा, आप सभी संदर्भ response करने के लिए एक synchronized ब्लॉक के अंदर इतना की तरह रख सकते हैं: जहां अपने अन्य धागा कतार के जवाब जोड़ रहा है

public void read() { 
    Boolean result = null; 
    synchronized (response) { 
     while (true) { 
      result = (Boolean) response.poll(); 
      if (result != null) break; 
      try { 
       response.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
       // You could put return; here 
      } 
     } 
    } 
    // result should always be non null here 
    if (result) { 
     view.dispose(); 
     LogInControler controler = new LogInControler(); 
     disableMasterLogin(); 
    } else { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JOptionPane.showMessageDialog(view.getRootPane(), "Wrong username or password"); 
       view.tfUsername.requestFocus(); 
      } 
     }); 
    } 
} 

सुनिश्चित करें कि एक सिंक्रनाइज़ ब्लॉक में भी है और notifyAll() कॉल कर:

public void addResult(Object result) { 
    synchronized (response) { 
     response.add(result); 
     response.notifyAll(); 
    }  
} 
+0

इसके अलावा मैंने 'JOptionPane.showMessageDialog() 'और' requestFocus() 'को कॉल करने के लिए कॉल के अंदर रखा है क्योंकि उन्हें केवल ईडीटी पर ही कॉल किया जाना चाहिए। –

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