2011-03-01 27 views
6

जावाडोक में कहा कि उपज विधिविधि कैसे काम करती है?

वर्तमान में क्रियान्वित धागा वस्तु अस्थायी रूप से रोक सकते हैं और अन्य थ्रेड निष्पादित करने के लिए अनुमति देने के लिए कारण बनता है।

और कैथरीन सिएरा और बर्ट बेट्स SCJP पुस्तक का कहना है कि

उपज() करने के लिए वर्तमान में चल रहे धागा सिर को पीछे runnable करने के लिए कर के लिए समान प्राथमिकता के अन्य धागे अनुमति देने के लिए किया गया है माना जाता है उनकी बारी ले लो।

तो वास्तव में विधि क्या कर रही है?

+1

मैं डॉन यहां एक प्रश्न नहीं देखें। आपके द्वारा उद्धृत दस्तावेज के बारे में आप क्या नहीं समझते? –

+0

मुझे लगता है कि एक ही प्राथमिकता के धागे में प्राथमिकता वाले धागे शामिल नहीं हैं, जो –

+4

कहलाते हैं, स्रोत कोड कहता है कि यह सभी 'सार्वजनिक स्थैतिक मूल शून्य उपज(); ': पी –

उत्तर

10

एक बहु थ्रेडेड एप्लिकेशन को देखते हुए, yield वर्तमान में निष्पादन को रोकने के लिए थ्रेड निष्पादित करने का कारण बनता है और प्रतीक्षा स्थिति में सेट किया जाएगा। JVM तब एक और थ्रेड चलाएगा जो पहले प्रतीक्षा स्थिति में था।

मुझे विश्वास है कि वही थ्रेड जो अभी पैदा हुआ है तकनीकी रूप से फिर से शुरू करने के लिए निर्धारित किया जा सकता है।

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

विस्तार से बता दें:

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

कॉलिंग उपज केवल जेवीएम को एक प्रतीक्षा स्थिति में रखने के लिए जेवीएम बताती है, भले ही JVM नहीं जा रहा था।

मैं एक उदाहरण का प्रयास करेगा:
निम्नलिखित समय के साथ 2 धागे के निष्पादन के लिए एक बहुत ही सरल उदाहरण है (मान 1 कोर) -

Thread\Time 1 2 3 4 5 6 7 8 9 
Thread 1 -----------  -----   ------- 
Thread 2    -------  ----------  ------ 

जब भी आप एक '-' मतलब यह है कि एक धागा है देखना क्रियान्वित। एक ' ' का मतलब है कि धागा इंतजार कर रहा है। जैसा कि आप देख सकते हैं, केवल एक ही समय में केवल 1 धागा चल सकता है। तो, जबकि 1 रन, जबकि दूसरा इंतजार कर रहा है। क्या उपज का उद्देश्य अन्य धागे को वर्तमान में चल रहे थ्रेड से आगे बढ़ने का मौका देना है।

+0

+1 मुझे हमेशा 'उपज()' के बारे में सोचने के लिए काफी उपयोगी लगता है क्योंकि शेड्यूलर के लिए संकेत मिलता है। (मुझे पता है कि यह तकनीकी रूप से एक संकेत नहीं है, लेकिन कई मायनों में यह एक जैसा व्यवहार करता है।) – biziclop

+0

जावा विनिर्देश के अनुसार, 'उपज() 'नो-ऑप हो सकता है। यदि आप उपज को मजबूर करना चाहते हैं, तो आप 'Thread.sleep (1) 'को आजमा सकते हैं। हालांकि, केवल दुर्लभ मामलों में इस तरह के उपयोग की आवश्यकता है। –

+0

@ एनो, क्या आप इस लाइन की पुष्टि कर रहे हैं- "मुझे विश्वास है कि वही थ्रेड जो अभी पैदा हुआ है तकनीकी रूप से फिर से शुरू करने के लिए निर्धारित किया जा सकता है।" – jjnguy

1

थ्रेड राज्यों में तैयार हो सकते हैं (चलने योग्य), अवरुद्ध (उदा।, कुछ आईओ खत्म होने की प्रतीक्षा कर रहे हैं), या चल रहे हैं; यह सभी थ्रेड कार्यान्वयन के लिए आम है, हालांकि कुछ विशेष कार्यान्वयन में अधिक राज्य हो सकते हैं।

यील्ड थ्रेड को चलाने योग्य से चलने का कारण बनता है, और शेड्यूलर को भविष्य में इसे फिर से चलाने के लिए बदलने की प्रतीक्षा करता है। एससीजेपी पुस्तक में इसका मतलब है।

धागे के लिए, ऐसा लगता है कि यह थोड़ी देर के लिए रुक गया है, जैसा कि जावाडोक में वर्णित है। तो दोनों कथन सही हैं, बस अलग-अलग वाक्यांश।

1

yield() आमतौर पर तब होता है जब आप कुछ होने के लिए धागे पर इंतजार कर रहे हैं लेकिन while(condition){ ...} जैसे कुछ के साथ सीपीसी चक्र को अवरुद्ध नहीं करना चाहते हैं।जिस तरह उपज() काम प्लेटफ़ॉर्म से प्लेटफ़ॉर्म तक भिन्न होता है और थ्रेड शेड्यूलर पर निर्भर करता है और आपको किसी विशेष तरीके से व्यवहार करने पर भरोसा नहीं करना चाहिए।

1

यह सहकारी मल्टीटास्किंग के समय से निकलता है। मूल विचार है, प्रोसेसर जब तक केवल एक ही धागे कार्यान्वित: किसी वस्तु के लिए इंतज़ार कर,

  1. इस सूत्र समाप्त होता है
  2. इस सूत्र कुछ अवरुद्ध आपरेशन, object.wait() या Thread.sleep की तरह, कुछ आईओ संचालन पर इंतजार कर पूरा करने के लिए करता है मॉनिटर, या इसी तरह के।
  3. यह धागा Thread.yield() को आमंत्रित करता है।

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

आधुनिक वीएम थ्रेड स्विचिंग किसी भी बिंदु पर हो सकता है, न केवल इन सूचीबद्ध, धागे भी एक साथ मार डाला हो, तो यह वास्तव में आवश्यक नहीं है, और कुछ VMs इसे पूरी तरह अनदेखा कर सकते हैं (System.gc() के समान है।)

+0

आपने किसी भी अवरुद्ध आईओ और लॉकस्पपोर्ट.park को छोड़ दिया है, जहां एक थ्रेड – bestsss

+0

@bestsss को जमानत दे सकता है: ब्लॉकिंग आईओ का उल्लेख किया गया है ("कुछ आईओ ऑपरेशन को पूरा करने के लिए इंतजार कर रहा है"), और LockSupport.park को "या इसी तरह" में शामिल किया गया है। लेकिन मुझे लगता है कि उपज() वर्ग तब तक अस्तित्व में नहीं था जब उपज() आवश्यक था। –

+0

ŭlo, मेरा बुरा, आईओ मेरे दिमाग में फिसल गया है। लॉकसपोर्ट 1.5 में पेश किया गया था (विधि प्रभावी रूप से 'Unsafe.park'' कहती है), थ्रेड.एल्ड जावा की शुरुआत के बाद से उपलब्ध है। – bestsss

1

उपज() विधि सुनिश्चित करें कि एक आवेदन में सभी एक ही प्राथमिकता धागे starvation का कारण नहीं होता वहाँ बनाने के लिए है। उदाहरण के लिए एक आवेदन में पांच धागे हैं और वे सभी एक ही प्राथमिकता के हैं। अब मान लीजिए कि एक थ्रेड को चलाने का मौका मिला है और यह धागा अपने काम को पूरा करने में इतना लंबा समय ले रहा है और इसलिए अन्य धागे को चलाने का मौका नहीं मिलता है। तो इस तरह की स्थितियों से बचने के लिए उपज() बचाव के लिए है।

1

अंत में, इस तरह ओएस विधियों, जो सिद्धांत रूप में रन कतार में वापस काम ही डाल में और अगले काम चलने देने के लिए बुला में करने के लिए yield() परिणाम कॉल (source):

/** 
    * sys_sched_yield - yield the current processor to other threads. 
    * 
    * This function yields the current CPU to other tasks. If there are no 
    * other threads running on this CPU then this function will return. 
    */ 
SYSCALL_DEFINE0(sched_yield) 
{ 
     /* 
     * lock this runqueue and disable interrupts. 
     */ 
     struct rq *rq = this_rq_lock(); 

     schedstat_inc(rq, yld_count); 
     current->sched_class->yield_task(rq); 

     /* 
      * Since we are going to call schedule() anyway, there's 
      * no need to preempt or enable interrupts: 
      */ 
     __release(rq->lock); 
     spin_release(&rq->lock.dep_map, 1, _THIS_IP_); 
     _raw_spin_unlock(&rq->lock); 
     preempt_enable_no_resched(); 

     schedule(); 

     return 0; 
} 
संबंधित मुद्दे