आंद्रेई पैंगिन द्वारा इस समस्या का एक उत्कृष्ट विवरण है , दिनांक 07 अप्रैल 2015 तक। यह यहां उपलब्ध है , लेकिन यह रूसी में लिखा गया है (मैं वैसे भी कोड नमूनों की समीक्षा करने का सुझाव देता हूं - वे अंतरराष्ट्रीय हैं)। क्लास इनिशियलाइजेशन के दौरान सामान्य समस्या ताला है।
लेख के कुछ उद्धरण इस प्रकार हैं:
जेएलएस के अनुसार , हर वर्ग के पास एक विशिष्ट इनिशियलाइज़ेशन लॉक होता है जिसे इनिशियलाइज़ेशन के दौरान कैप्चर किया जाता है। जब अन्य थ्रेड इनिशियलाइज़ेशन के दौरान इस क्लास को एक्सेस करने की कोशिश करता है, तो इसे इनिशियलाइज़ेशन पूरा होने तक लॉक पर ब्लॉक किया जाएगा। जब कक्षाएं समवर्ती रूप से आरंभ की जाती हैं, तो गतिरोध प्राप्त करना संभव है।
मैंने एक साधारण प्रोग्राम लिखा जो पूर्णांक की राशि की गणना करता है, इसे क्या प्रिंट करना चाहिए?
public class StreamSum {
static final int SUM = IntStream.range(0, 100).parallel().reduce((n, m) -> n + m).getAsInt();
public static void main(String[] args) {
System.out.println(SUM);
}
}
अब कॉल के parallel()
साथ लैम्ब्डा को हटा दें या बदल दें Integer::sum
- क्या बदल जाएगा?
यहाँ हम फिर से गतिरोध को देखते हैं [पहले लेख में कक्षा शुरुआती में गतिरोध के कुछ उदाहरण थे]। क्योंकि parallel()
स्ट्रीम ऑपरेशन एक अलग थ्रेड पूल में चलते हैं। ये धागे लैम्ब्डा बॉडी को निष्पादित करने की कोशिश करते हैं, जिसे क्लास के private static
अंदर एक विधि के रूप में बाईटेकोड में लिखा जाता है StreamSum
। लेकिन इस विधि को वर्ग स्थिर इनिशियलाइज़र के पूरा होने से पहले निष्पादित नहीं किया जा सकता है, जो स्ट्रीम पूरा होने के परिणामों की प्रतीक्षा करता है।
अधिक माइंडब्लोइंग क्या है: यह कोड अलग-अलग वातावरण में अलग-अलग तरीके से काम करता है। यह एक एकल सीपीयू मशीन पर सही ढंग से काम करेगा और बहु सीपीयू मशीन पर लटकाएगा। यह अंतर फोर्क-जॉइन पूल कार्यान्वयन से आता है। आप पैरामीटर को बदलते हुए इसे स्वयं सत्यापित कर सकते हैं-Djava.util.concurrent.ForkJoinPool.common.parallelism=N