2012-01-27 8 views
6

मैंने एक टेस्ट ऐप लिखा है जिसे कभी नहीं रोकना चाहिए। यह t.wait() (tThread ऑब्जेक्ट है) जारी करता है, लेकिन मैं कभी भी सूचित नहीं करता हूं। यह कोड क्यों समाप्त होता है? t पर सिंक्रनाइज़ करने वाले मुख्य थ्रेड के बावजूद, स्पॉन्टेड थ्रेड चलता है, इसलिए यह इस ऑब्जेक्ट को लॉक नहीं करता है।क्या जावा प्रतीक्षा थ्रेड को स्पष्ट रूप से सूचित करता है?

public class ThreadWait { 
    public static void main(String sArgs[]) throws InterruptedException { 
     System.out.println("hello"); 
     Thread t = new MyThread(); 
     synchronized (t) { 
      t.start(); 
      Thread.sleep(5000); 
      t.wait(); 
      java.lang.System.out.println("main done"); 
     } 
    } 
} 

class MyThread extends Thread { 
    public void run() { 
     for (int i = 1; i <= 5; i++) { 
      java.lang.System.out.println("" + i); 
      try { 
       Thread.sleep(500); 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 
} 

नतीजा यह है कि मुख्य थ्रेड 5 सेकंड इंतजार कर रहा है और इस समय के दौरान कार्यकर्ता इसके उत्पादन देता है। फिर 5 सेकंड समाप्त होने के बाद, कार्यक्रम निकलता है। t.wait() इंतजार नहीं करता है। यदि मुख्य धागा 5 सेकंड (इस लाइन पर टिप्पणी करने) के लिए सो नहीं जाएगा, तो t.wait() वास्तव में कार्यकर्ता समाप्त होने तक प्रतीक्षा करेगा। बेशक, join() यहां उपयोग करने का एक तरीका है, लेकिन, अप्रत्याशित रूप से, wait()join() जैसा ही काम करता है। क्यूं कर?

शायद JVM देखता है के बाद से केवल एक धागा चल रहा है, वहाँ मुख्य थ्रेड सूचित करने के लिए कोई संभावना नहीं है और गतिरोध को हल करती है कि,। यदि यह सच है, तो क्या यह एक दस्तावेज सुविधा है?

Windows XP पर परीक्षण कर रहा हूँ, जावा 6.

+0

क्या जब होता है आप केवल 1 या 2 सेकंड के लिए सोने के? तो मैं शर्त लगाता हूं कि आपके पास थ्रेड टी के लिए चलने के लिए मुख्य धागा इंतजार होगा ... – Renato

उत्तर

9

आप एक Thread पर प्रतीक्षा कर रहे हैं - और सबसे वस्तुओं परोक्ष अधिसूचित नहीं हैं, एक Thread वस्तु अधिसूचित किया गया है, जबकि जब धागा समाप्त हो जाता है। (मैं इसके लिए देख रहा हूँ ...) यह कहीं दस्तावेज़ीकरण किया गया है कि आप नहीं उपयोग Thread वस्तुओं पर wait/notify, के रूप में है कि आंतरिक रूप से किया है चाहिए।

यह एक अच्छा उदाहरण है कि क्यों सिंक्रनाइज़ेशन (और प्रतीक्षा/सूचित करें) के लिए "निजी" ऑब्जेक्ट का उपयोग करना सबसे अच्छा अभ्यास है - कुछ केवल आपका कोड जानता है। ।

private final Object lock = new Object(); 

(सामान्य में, हालांकि, यह करता है, तो आप कर सकते हैं java.util.concurrent द्वारा प्रदान के रूप में टिप्पणी में उल्लेख किया उच्च स्तर कपोल-कल्पना से कुछ का उपयोग करने के लिए क्लीनर है, यह भी एक अच्छा है: मैं आमतौर पर की तरह कुछ का उपयोग विचार Thread खुद के प्रदान की तुलना Runnable बल्कि लागू करने के लिए।)

+0

थ्रेड में कई विधि उस ऑब्जेक्ट पर सिंक्रनाइज़ हैं और प्रतीक्षा/सूचित करें, इसलिए नकली जागने की अपेक्षा की जानी चाहिए। थ्रेड का विस्तार न करने के लिए भी एक अच्छा अभ्यास है, लेकिन एक थ्रेड द्वारा लिपटे एक रननेबल का उपयोग करने के लिए। यह इस मुद्दे से भी बच जाएगा। –

+1

@ पीटर Lawrey: जब तक ओपी तब तक चलने योग्य पर प्रतीक्षा/अधिसूचित नहीं किया गया था, धागे पर नहीं :) मैं अभी भी एक "गूंगा" वस्तु पसंद करना पसंद करता हूं जिसे मैं व्यक्तिगत रूप से * कहीं और * नहीं दिखाता हूं। –

+0

आदर्श रूप से, आप दोनों चाहते हैं क्योंकि आप नहीं जानते कि भविष्य में कोड कैसे बदला जा सकता है। आईएमएचओ में कई रणनीतियां हैं जो सर्वोत्तम अभ्यास हैं आपके कोड को बेहतर तरीके से सुरक्षित करती हैं। –

8

JavaDocwait के लिए इस सवाल का जवाब देता है: नकली wakeups संभव हो रहे हैं। इसका अर्थ यह है कि JVM जब भी चाहें wait पर कॉल समाप्त करने के लिए स्वतंत्र है।

प्रलेखन आपको एक समाधान भी देता है यदि आप यह नहीं चाहते हैं (जो शायद हमेशा मामला है): कॉल को wait पर लूप में रखें और जांचें कि आप जिस स्थिति की प्रतीक्षा कर रहे हैं, वह हर जागरूकता के बाद सच हो गया है या नहीं।

+3

@ बोरीस एक नकली wakeupup के मामले में, कोई अपवाद नहीं है। थ्रेड बाधित होने पर केवल 'इंटरप्टेड एक्सेप्शन' फेंक दिया जाता है। –

+2

मुझे संदेह है कि यह वास्तव में * एक नकली जागरूकता है - मेरा मानना ​​है कि यह विशेष रूप से 'थ्रेड' पर प्रतीक्षा करने का व्यवहार है; थ्रेड समाप्त होने पर यह * अधिसूचित किया जाएगा। यह सामान्य अर्थ में नकली नहीं है। –

+2

मॉनिटर पैटर्न (या इसके किसी भी प्रकार के) के साथ भी नकली वेकअप के बिना, आप हमेशा लूप करना चाहते हैं और शर्तों की जांच करना चाहते हैं। यदि आप बाद में एक और शर्त जोड़ते हैं तो समस्याएं रोकती हैं (जावा और सी # मॉनीटर एक ऑब्जेक्ट को लॉक और कंडीशन वैरिएबल दोनों के रूप में उपयोग करते हैं, इसलिए आप प्रति शर्त एक शर्त चर का उपयोग नहीं कर सकते हैं)। यह स्थिति को पूरा करने पर प्रक्रिया से आपको रोकता है, लेकिन एक ही वस्तु पर एक और धागा इंतजार कर रहा है, और अब स्थिति अब सच नहीं है। –

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