ओपी के सवाल का जवाब दे रहे हैं
एक यादृच्छिक घटना के लिए हमेशा इंतजार किए बिना इस प्रतीक्षा को जगाने के लिए मैं क्या कर सकता हूं?
, कोई भी स्पिरिट वेकअप इस प्रतीक्षित धागे को नहीं जगा सका!
भले ही ओपी के स्निपेट के मामले में किसी विशेष प्लेटफॉर्म पर स्प्यूरियस वेकअप हो या न हो, यह सकारात्मक रूप से असंभव हैCondition.await()
वापसी के लिए और " " को देखने के ! आउटपुट स्ट्रीम में।
जब तक आप बहुत ही विदेशी जावा क्लास लाइब्रेरी का उपयोग नहीं कर रहे हैं
इसका कारण यह है मानक, है OpenJDK के ReentrantLock
की विधि newCondition()
रिटर्न AbstractQueuedSynchronizer
'की रों कार्यान्वयन Condition
इंटरफेस, नेस्ट ConditionObject
(वैसे, इसके बारे में केवल कार्यान्वयन है Condition
इस वर्ग के पुस्तकालय में इंटरफ़ेस), और ConditionObject
की विधि await()
ही जाँच करता है कि हालत नहीं है धारण और कोई भी स्पिरिट वेकप इस पद्धति को गलती से वापस करने के लिए मजबूर नहीं कर सकता है।
वैसे, आप इसे स्वयं जांच सकते हैं क्योंकि -बेड AbstractQueuedSynchronizer
कार्यान्वयन में शामिल होने के बाद, यह बहुत ही आसान है कि यह बहुत ही अजीब है।
AbstractQueuedSynchronizer
निम्न-स्तर LockSupport
के तरीकों park
और unpark
विधियों का उपयोग करता है , और यदि आप LockSupport.unpark
प्रतीक्षा कर रहे एक थ्रेड पर आह्वान करते हैं Condition
, तो इस क्रिया को एक सहज जागरण से अलग नहीं किया जा सकता है।
ओपी के स्निपेट को थोड़ा सा दर्शाते हुए,
public class Spurious {
private static class AwaitingThread extends Thread {
@Override
public void run() {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
private static final int AMOUNT_OF_SPURIOUS_WAKEUPS = 10;
public static void main(String[] args) throws InterruptedException {
Thread awaitingThread = new AwaitingThread();
awaitingThread.start();
Thread.sleep(10000);
for(int i =0 ; i < AMOUNT_OF_SPURIOUS_WAKEUPS; i++)
LockSupport.unpark(awaitingThread);
Thread.sleep(10000);
if (awaitingThread.isAlive())
System.out.println("Even after " + AMOUNT_OF_SPURIOUS_WAKEUPS + " \"spurious wakeups\" the Condition is stil awaiting");
else
System.out.println("You are using very unusual implementation of java.util.concurrent.locks.Condition");
}
}
, और कोई फर्क नहीं पड़ता कि कितना मुश्किल unparking (मुख्य) धागा प्रतीक्षा करने वाले धागे को जगाने की कोशिश करेगा, Condition.await()
इस मामले में विधि कभी वापस नहीं आएगी।
इंटरफ़ेस के जावदॉक में शानदार वेकअप के Condition
तरीकों पर चर्चा की गई Condition
है । यद्यपि यह कहता है कि,
जब किसी शर्त पर प्रतीक्षा की जाती है, तो एक स्पुरियस वेकअप होने की अनुमति होती है
और वह
यह अनुशंसा की जाती है कि एप्लिकेशन प्रोग्रामर हमेशा यह मान लें कि वे हो सकते हैं और इसलिए हमेशा एक लूप में प्रतीक्षा करें।
लेकिन यह बाद में जोड़ता है
स्पुरियस वेकअप की संभावना को दूर करने के लिए एक कार्यान्वयन मुफ्त है
और इंटरफ़ेस का AbstractQueuedSynchronizer
क्रियान्वयन Condition
ठीक वही करता है - जो कि उठने की किसी भी संभावना को दूर करता है ।
यह निश्चित रूप से अन्य ConditionObject
प्रतीक्षित विधियों के लिए सही है ।
तो, निष्कर्ष है:
हमें हमेशा Condition.await
लूप में कॉल करना चाहिए और जांच करनी चाहिए कि क्या स्थिति नहीं है, लेकिन मानक के साथ, OpenJDK, जावा क्लास लाइब्रेरी कभी नहीं हो सकता है । जब तक, फिर से, आप बहुत ही असामान्य जावा क्लास लाइब्रेरी का उपयोग करते हैं (जो बहुत ही असामान्य होना चाहिए, क्योंकि एक अन्य प्रसिद्ध गैर-ओपनजेडके जावा क्लास लाइब्रेरी, वर्तमान में लगभग विलुप्त हो चुकी जीएनयू क्लासपाथ और अपाचे हार्मनी , Condition
इंटरफ़ेस के मानक कार्यान्वयन के समान है )
pthread_cond_wait()
और असली सवाल का उपयोग करते हैं, "pthread_cond_wait में क्यों अजीब जगहें हैं?" ।