2012-02-27 22 views
58

से अधिक थ्रेड println (स्ट्रिंग) तुल्यकालन के बिना कॉल करते हैं, उत्पादन interleaved कर सकते हैं? API तुल्यकालन की कोई जिक्र नहीं है, तो यह संभव लगता है, या interleaved उत्पादन और/या वी एम स्मृति मॉडल बफ़रिंग, आदि द्वारा रोका जाता है?तुल्यकालन और System.out.println

संपादित करें:

उदाहरण के लिए, प्रत्येक थ्रेड शामिल है:

System.out.println("ABC"); 

उत्पादन होने की गारंटी है:

ABC 
ABC 

या यह हो सकता है:

AABC 
BC 
+0

हमेशा पहले। लेकिन @ जॉन विंट के जवाब को पढ़ें, क्योंकि आप शायद कंसोल पर तारों को फेंकना नहीं चाहते हैं। – parkovski

+4

ध्यान रखें कि यहां तक ​​कि यदि System.out.println और System.err.println दोनों सिंक्रनाइज़ किए गए हैं, तो इन दोनों को अपने बीच सिंक्रनाइज़ नहीं किया गया है, इसलिए System.err.println आपको System.out.println के साथ इंटरलव कर सकता है जो आपको कंसोल दे सकता है आप क्या उम्मीद करते हो। – Pacerier

+0

असल में मैं अक्सर इंटेलिज आइडिया और एक्लिप्स में इंटरलीव आउटपुट (आपका प्रदर्शन केस 2) प्राप्त करता हूं, अन्य लोग आपको क्या बता रहे हैं (jdk 1.6)। – mucaho

उत्तर

54

बाद API दस्तावेज़ System.out object पर धागा सुरक्षा के कोई जिक्र नहीं है और न ही PrintStream#println(String) methodआप कल्पना नहीं कर सकते कि यह धागा सुरक्षित है करता है।

हालांकि, यह पूरी तरह संभव है एक विशेष JVM की अंतर्निहित कार्यान्वयन println विधि के लिए एक धागा सुरक्षित समारोह का उपयोग करता है (उदाहरण के लिए printf on glibc) ताकि, वास्तव में, उत्पादन अपने पहले उदाहरण प्रति गारंटी हो जाएगा (हमेशा ABC\n फिर ABC\n, कभी भी आपके दूसरे उदाहरण के प्रति अक्षर छेड़छाड़ नहीं किया गया)। लेकिन ध्यान रखें कि बहुत सारे JVM कार्यान्वयन हैं और उन्हें केवल उस जेवीएम विनिर्देश का पालन करना आवश्यक है, न कि उस spec के बाहर किसी भी सम्मेलन।

आप बिल्कुल यह सुनिश्चित करना चाहिए अगर वह के रूप में आप तो वर्णन आप मैन्युअल रूप से पारस्परिक अपवर्जन लागू करना चाहिए, उदाहरण के लिए कोई println कॉल गिरा देगा:

public void safePrintln(String s) { 
    synchronized (System.out) { 
    System.out.println(s); 
    } 
} 
बेशक

, इस उदाहरण केवल एक उदाहरण है और नहीं करना चाहिए एक "समाधान" के रूप में लिया जाना चाहिए; विचार करने के लिए कई अन्य कारक हैं। उदाहरण के लिए, ऊपर safePrintln(...) विधि केवल सुरक्षित है यदि सभी कोड उस विधि का उपयोग करता है और कुछ भी System.out.println(...) पर सीधे कॉल नहीं करता है।

+1

डाउनवोट के बारे में डुनो, लेकिन ऐसा लगता है कि प्रिंट इत्यादि के लिए मानक कार्यान्वयन प्रिंटस्ट्रीम पर लेखन विधि को कॉल करता है जो सिंक्रनाइज़ ब्लॉक में पहले से ही लपेटा गया है। इस प्रकार पात्रों को मिश्रण में जोड़कर जिबर्निश प्रिंट करना संभव नहीं होगा, यह केवल वह क्रम है जिसमें तार मुद्रित होते हैं जो प्रभावित हो सकते हैं। –

+3

@Grep: सुनिश्चित करें कि, मैं सिर्फ बनाम आम * कार्यान्वयन * (जो की संभावना सिंक्रनाइज़ किए जाते हैं) दस्तावेज * इंटरफ़ेस * के बीच का अंतर (जो तुल्यकालन का कोई वादा करता है) के बारे में पंडिताऊ जा रहा हूँ। – maerics

+0

एक कैसे व्याख्या नहीं करता कि 'के कार्यान्वयन वास्तव में println' (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/ [बहुत बात आप का वर्णन करता है] जावा/आईओ/प्रिंटस्ट्रीम.जावा? एवी = एफ # 804) यहाँ? क्या यह आपके समाधान के समान ही नस में इसे थ्रेड-सुरक्षित नहीं बनाता है? – Makoto

7

जब तक आप नहीं करते हैं System.setOut के माध्यम से बदलें यह धागा सुरक्षित है।

हालांकि यह सुरक्षित थ्रेड है आप कई धागे System.out ऐसी है कि

Thread-1 
    System.out.println("A"); 
    System.out.println("B"); 
    System.out.println("C"); 
Thread-2 
    System.out.println("1"); 
    System.out.println("2"); 
    System.out.println("3"); 

के लिए लिख अन्य संयोजन के बीच

1 
2 
A 
3 
B 
C 

पढ़ सकते हैं हो सकता है। यह OutputStream उदाहरण पर एक ताला प्राप्त कर लेता है - - यह तो बफर और तुरंत फ्लश करने के लिए लिखेंगे

जब आप System.out पर लिखें:

तो अपने सवाल का जवाब देने।

एक बार जब यह अवरोध समाप्त, OutputStream प्लावित और करने के लिए लिखा है। ऐसा कोई उदाहरण नहीं होगा जहां आपके पास 1A 2B जैसे विभिन्न स्ट्रिंग शामिल होंगी।

कि System.out.println साथ नहीं होगा: अपना संपादन जवाब देने के लिए

संपादित करें। चूंकि PrintStream पूरे समारोह सिंक्रनाइज़ करता है, यह बफर भर जाएगा और फिर इसे atomically फ्लश। आने वाले किसी भी नए धागे के साथ काम करने के लिए अब एक नया बफर होगा।

+0

उत्तर के लिए धन्यवाद, लेकिन मुझे लगता है कि आपने मेरे प्रश्न को गलत समझा। मैंने इसे स्पष्ट करने की कोशिश की है। –

+0

हाँ मैंने जवाब दिया कि नीचे मैं इसे और अधिक स्पष्ट कर सकता था। –

+1

क्या वहां कुछ दस्तावेज हैं जो आपको विश्वास करते हैं कि आउटपुटस्ट्रीम इंस्टेंस पर लॉक अधिग्रहण किया गया है? – maerics

2

बस स्पष्ट करने के लिए, कहें कि आपके पास दो धागे हैं, जो "ABC" प्रिंट करता है और दूसरा जो "DEF" प्रिंट करता है। आप की तरह इस आउटपुट प्राप्त कभी नहीं होगा: ADBECF, लेकिन आप प्राप्त कर सकते हैं या तो

ABC 
DEF 

या

DEF 
ABC 
+0

यह प्रिंट के साथ ही होगा, प्रिंटल नहीं। Println परमाणु रूप से मुद्रित होगा तो एक नई लाइन लिखें। तो आपके पास 'एबीसी' से ऊपर 'एबीसी' या 'एबीसी' –

+0

@ पार्कोव्स्की के ऊपर' डीईसी' होगा, आपके उत्तर के लिए धन्यवाद, लेकिन क्या आप समझा सकते हैं कि आउटपुट क्यों नहीं है कि आउटपुट नहीं किया जाएगा? –

14

OpenJDK स्रोत कोड आपके प्रश्न के उत्तर:

public void println(String x) { 
    synchronized (this) { 
     print(x); 
     newLine(); 
    } 
} 

संदर्भ: http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/39e8fe7a0af1/src/share/classes/java/io/PrintStream.java

+2

धन्यवाद, हालांकि मैं जानना चाहता था कि इंटरफ़ेस गारंटीकृत सिंक्रनाइज़ेशन है या नहीं, वर्तमान कार्यान्वयन (जिसे बदला जा सकता है) सिंक्रनाइज़ेशन प्रदान करता है या नहीं। –

+1

फिर "सिंक्रनाइज़" कीवर्ड के बिना println() की घोषणा ने यह स्पष्ट कर दिया है कि यह सिंक्रनाइज़ेशन की गारंटी नहीं देता है। कार्यान्वयन आगे साबित करता है। – zzhang

+2

मैंने डाउनवॉट किया है क्योंकि आप कंक्रीट कार्यान्वयन से विनिर्देश (यानी अन्य कार्यान्वयन के व्यवहार) का अनुमान लगाते हैं, भले ही आपको यह याद दिलाया गया कि आप ऐसा नहीं कर सकते हैं। आपका कार्यान्वयन वास्तव में साबित करता है कि सिंक्रनाइज़ेशन गारंटी प्राप्त करने के लिए घोषणा में सिंक कीवर्ड आवश्यक नहीं है। तो, जो भी आप दावा करते हैं वह पूरी तरह से तर्क और आपके स्वयं के उदाहरण के खिलाफ है। – Val

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