2008-10-08 14 views
22

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

किस स्थिति में स्विंग थ्रेड सुरक्षित नहीं है?

मुझे सक्रिय रूप से क्या करना चाहिए?

उत्तर

26
  1. बटन, ईवेंट इत्यादि के जवाब में लंबे समय तक चलने वाले कार्यों को कभी भी नहीं करें क्योंकि ये ईवेंट थ्रेड पर हैं। यदि आप ईवेंट थ्रेड को अवरुद्ध करते हैं, तो संपूर्ण जीयूआई पूरी तरह से उत्तरदायी नहीं होगा जिसके परिणामस्वरूप उपयोगकर्ताओं ने वास्तव में बंद कर दिया है। यही कारण है कि स्विंग धीमी और क्रिस्टी लगती है।

  2. ईडीटी (ईवेंट प्रेषण धागा) पर कार्य चलाने के लिए थ्रेड, एक्जिक्यूटर्स और स्विंगवर्कर का उपयोग करें।

  3. ईडीटी के बाहर विजेट अपडेट या निर्माण न करें। ईडीटी के बाहर आप केवल एकमात्र कॉल कर सकते हैं Component.repaint()। EDT पर कुछ कोड निष्पादित करने के लिए SwingUtilitis.invokeLater का उपयोग करें।

  4. उपयोग EDT Debug Techniques और एक स्मार्ट रंगरूप (Substance की तरह है, जो EDT उल्लंघन के लिए जाँच करता है)

आप इन नियमों का पालन करते हैं, तो स्विंग कुछ बहुत ही आकर्षक बना सकता है और उत्तरदायी GUIs

एक कुछ वास्तव में भयानक स्विंग यूआई कार्य का उदाहरण: Palantir Technologies। नोट: मैं उनके लिए काम नहीं करता, सिर्फ भयानक स्विंग का एक उदाहरण। कोई सार्वजनिक डेमो शर्मिंदा नहीं है ... उनके blog भी अच्छे हैं, स्पैस, लेकिन अच्छे

+1

एक invokeAndWait() विधि भी है, लेकिन जब भी संभव हो invocLater() का उपयोग करें। – Powerlord

+1

यदि आप डेडलॉक्स चाहते हैं तो invokeAndWait का उपयोग करें। ;) –

+0

या घंटे के हिसाब से भुगतान किया जाता है। :-) –

3

घटना प्रेषण धागे को छोड़कर सक्रिय रूप से किसी भी स्विंग कार्य करने से बचें। स्विंग को विस्तारित करने के लिए लिखा गया था और सूर्य ने फैसला किया कि इसके लिए एकल-थ्रेडेड मॉडल बेहतर था।

मुझे ऊपर मेरी सलाह का पालन करते समय कोई समस्या नहीं है। कुछ परिस्थितियां हैं जहां आप अन्य धागे से 'स्विंग' कर सकते हैं लेकिन मुझे कभी आवश्यकता नहीं मिली है।

8

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

तो, ईडीटी पर सभी स्विंग मैनिप्लेशंस करें। नोट EDT धागे पर मुख्य कहा जाता है नहीं है, इसलिए इस बॉयलरप्लेट की तरह अपने (सरल) घुमाओ अनुप्रयोगों शुरू:

class MyApp { 
    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { public void run() { 
      runEDT(); 
     }}); 
    } 
    private static void runEDT() { 
     assert java.awt.EventQueue.isDispatchThread(); 
     ... 
+0

+1 थ्रेड-विरोधी – Fortega

2

आप जावा 6 उपयोग कर रहे हैं तो SwingWorker निश्चित रूप से इस से निपटने के लिए सबसे आसान तरीका है ।

असल में आप यह सुनिश्चित करना चाहते हैं कि यूआई को बदलने वाला कुछ भी EventDispatchThread पर किया जाता है।

यह आपको यह बताने के लिए SwingUtilities.isEventDispatchThread() विधि का उपयोग करके पाया जा सकता है कि आप इसमें हैं (आमतौर पर एक अच्छा विचार नहीं है - आपको पता होना चाहिए कि थ्रेड सक्रिय है)।

यदि आप ईडीटी पर नहीं हैं तो आप EDT पर रननेबल को आमंत्रित करने के लिए SwingUtilities.invokeLater() और SwingUtilities.invokeAndWait() का उपयोग करें।

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

11

यह उन प्रश्नों में से एक है जो मुझे खुश करते हैं मैंने Robinson & Vorobiev's book on Swing खरीदा।

कुछ भी है कि एक java.awt.Component के राज्य तक पहुँचता तीन अपवादों के साथ, EDT अंदर चलाने की जानी चाहिए: कुछ भी विशेष रूप से धागे की सुरक्षित के रूप में दस्तावेज, इस तरह के repaint(), revalidate(), और invalidate() के रूप में; यूआई में कोई भी घटक जो अभी तक नहीं हुआ है; और ऐप्पल के start() से पहले एप्पल में किसी भी घटक को बुलाया गया है।

विशेष रूप से थ्रेड-सुरक्षित किए गए तरीके इतने असामान्य हैं कि अक्सर उन लोगों को याद रखने के लिए पर्याप्त होता है; आप आमतौर पर यह मानने से दूर हो सकते हैं कि ऐसी कोई विधि नहीं है (उदाहरण के लिए, स्विंगवर्कर में एक पुनर्निर्मित कॉल को लपेटना पूरी तरह से सुरक्षित है)।

एहसास मतलब यह है कि घटक है या तो एक उच्च-स्तरीय कंटेनर (JFrame की तरह) जो setVisible(true), show(), या pack() में से किसी पर बुलाया गया है, या यह एक एहसास हुआ घटक में जोड़ा गया है। इसका मतलब यह है कि मुख्य() विधि में अपना यूआई बनाने के लिए यह बिल्कुल ठीक है, क्योंकि कई ट्यूटोरियल उदाहरण करते हैं, क्योंकि वे शीर्ष-स्तरीय कंटेनर पर setVisible(true) पर कॉल नहीं करते हैं जब तक कि प्रत्येक घटक इसमें जोड़ा नहीं जाता है, फोंट और सीमाएं कॉन्फ़िगर की गई हैं, आदि।

इसी कारण से, अपने एप्लेट यूआई को init() विधि में बनाने के लिए पूरी तरह से सुरक्षित है, और उसके बाद start() को सभी निर्मित होने के बाद कॉल करें।

invokeLater() को भेजने के लिए Runnables में बाद में घटक परिवर्तनों को लपेटना इसे केवल कुछ बार करने के बाद सही हो जाता है। एक चीज जो मुझे परेशान करती है वह एक घटक की स्थिति पढ़ती है (कहें, someTextField.getText()) किसी अन्य थ्रेड से। तकनीकी रूप से, इसे invokeLater() में भी लपेटा जाना है; व्यावहारिक रूप से, यह कोड को बदसूरत तेज़ बना सकता है, और मैं अक्सर परेशान नहीं करता हूं, या मैं उस जानकारी को प्रारंभिक घटना हैंडलिंग समय पर पकड़ने के लिए सावधान हूं (आमतौर पर वैसे भी अधिकांश मामलों में इसे करने का सही समय)।

+2

के लिए +1 "एक यूआई में घटक जिसे अभी तक महसूस नहीं किया गया है" - अब अभ्यास की अनुशंसा नहीं की गई है। ईडीटी पर आपको हमेशा अपने घटकों के साथ काम करना चाहिए, भले ही उन्हें एहसास हो या नहीं। –

+1

मान लीजिए कि आप सही हैं, यह मुझे आश्चर्यचकित करता है कि वे इसकी अनुशंसा क्यों करेंगे। यह एक बड़ा बदलाव है, यह देखते हुए कि यह बड़ी मात्रा में ट्यूटोरियल कोड को कैसे प्रभावित करेगा। ... वास्तव में, मुझे इस सिफारिश को बनाने वाला कोई जावा 6 ट्यूटोरियल नहीं मिल सकता है; नमूना कोड अभी भी मुख्य धागे में यूआई बनाता है। क्या इसके लिए आपके पास स्रोत है? –

+1

@ पॉल 'टिस सच देखें http://stackoverflow.com/questions/491323/is-it-safe-to-construct-swing-awt-widgets-not-on-the-event-dispatch-thread/491377#491377 और अधिक। यह पूर्वदर्शी है, और यह एक दर्द है। – Pool

1

यहां मिंग स्विंग थ्रेड-फ्रींडली के लिए एक पैटर्न है।

सुब्लास एक्शन (माईएक्शन) और इसे करने के लिए कार्य किया गया है। कन्स्ट्रक्टर को स्ट्रिंग NAME ले जाएं।

इसे एक अमूर्त कार्रवाई Impl() विधि दें।

, अपने संवाद एक सभ्य अनुमान दिखा सकते हैं

doAction(){ 
new Thread(){ 
    public void run(){ 
    //kick off thread to do actionImpl(). 
     actionImpl(); 
     MyAction.this.interrupt(); 
    }.start(); // use a worker pool if you care about garbage. 
try { 
sleep(300); 
Go to a busy cursor 
sleep(600); 
Show a busy dialog(Name) // name comes in handy here 
} catch(interrupted exception){ 
    show normal cursor 
} 

आप समय कार्य के लिए लिया जाता है, और अगली बार रिकॉर्ड कर सकते हैं यह की तरह लग रहे हैं .. (स्यूडोकोड चेतावनी!)।

यदि आप वास्तव में अच्छा होना चाहते हैं, तो अन्य कार्यकर्ता धागे में भी सोएं।

2

वाक्यांश 'धागा-असुरक्षित' लगता है जैसे कुछ स्वाभाविक रूप से खराब है (आप जानते हैं ... 'सुरक्षित' - अच्छा; 'असुरक्षित' - बुरा)। हकीकत यह है कि थ्रेड सुरक्षा लागत पर आती है - थ्रेडसेफ ऑब्जेक्ट्स अक्सर लागू करने के लिए अधिक जटिल होते हैं (और स्विंग काफी जटिल है।)

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

आमतौर पर इसके बजाय क्या किया जाता है यह है कि जीयूआई थ्रेड-असफ़लता से निपटने का एक तरीका प्रदान करते हैं। जैसा कि अन्य ने नोट किया, स्विंग ने हमेशा कुछ सरल स्विंगउटिविटीज.inवोकलाटर() प्रदान किया है। जावा 6 में उत्कृष्ट स्विंगवर्कर शामिल है (Swinglabs.org से पिछले संस्करणों के लिए उपलब्ध)। स्विंग संदर्भ में धागे के प्रबंधन के लिए फॉक्सट्रॉट जैसे तीसरे पक्ष के पुस्तकालय भी हैं।

स्विंग की कुख्यातता इसलिए है क्योंकि डिजाइनरों ने यह मानने के हल्के हाथ से दृष्टिकोण लिया है कि डेवलपर सही काम करेगा और ईडीटी को बाहर नहीं करेगा या ईडीटी के बाहर से घटक संशोधित नहीं करेगा। उन्होंने अपनी थ्रेडिंग पॉलिसी को जोर से और स्पष्ट बताया है और यह डेवलपर्स पर इसका पालन करने के लिए है।

प्रत्येक स्विंग एपीआई को प्रत्येक संपत्ति-सेट, अमान्य, इत्यादि के लिए ईडीटी में नौकरी पोस्ट करने के लिए छोटा है, जो इसे थ्रेडसेफ बना देगा, लेकिन भारी मंदी की कीमत पर। आप एओपी का उपयोग करके इसे स्वयं भी कर सकते हैं। तुलना के लिए, जब किसी घटक को गलत थ्रेड से एक्सेस किया जाता है तो SWT अपवाद फेंकता है।

1

ध्यान दें कि मॉडल इंटरफेस भी थ्रेड सुरक्षित नहीं हैं। आकार और सामग्री को अलग-अलग तरीके से पूछताछ की जाती है और इसलिए उनको सिंक्रनाइज़ करने का कोई तरीका नहीं है।

किसी अन्य थ्रेड से मॉडल की स्थिति को अपडेट करने से यह कम से कम एक स्थिति पेंट कर सकता है जहां आकार अभी भी बड़ा है (तालिका पंक्ति अभी भी मौजूद है), लेकिन सामग्री अब और नहीं है।

ईडीटी में हमेशा मॉडल की स्थिति अपडेट करना इन से बचाता है।

1

invokeLater() और invokeAndWait() वास्तव में उपयोग किया जाना चाहिए जब आप किसी भी थ्रेड से जीयूआई घटकों के साथ कोई बातचीत कर रहे हैं जो ईडीटी नहीं है।

यह विकास के दौरान काम कर सकता है, लेकिन अधिकांश समवर्ती बग की तरह, आप अजीब अपवादों को देखना शुरू कर देंगे जो पूरी तरह से असंबंधित प्रतीत होते हैं, और गैर-निर्धारक रूप से होते हैं - आमतौर पर वास्तविक उपयोगकर्ताओं द्वारा भेजे जाने के बाद देखा जाता है। अच्छा नही।

इसके अलावा, आपको कोई भरोसा नहीं है कि आपका ऐप भविष्य में सीपीयू पर अधिक से अधिक कोर के साथ काम करना जारी रखेगा - जो अजीब थ्रेडिंग मुद्दों का सामना करने के लिए अधिक प्रवण हैं क्योंकि उनके द्वारा ओएस द्वारा अनुकरण किए जाने के बजाय वास्तव में समवर्ती होने के कारण ।

हां, यह एक रननेबल इंस्टेंस में ईडीटी में वापस हर विधि कॉल को बदसूरत लपेटता है, लेकिन यह आपके लिए जावा है। जब तक हम बंद नहीं हो जाते, आपको बस इसके साथ रहना पड़ता है।

1

थ्रेडिंग के बारे में अधिक जानकारी के लिए, एलन होलब द्वारा जावा थ्रेड्स को टमिंग करना एक पुरानी किताब है लेकिन एक महान पढ़ा है।

होलब, वास्तव में उत्तरदायी यूआई और विवरण उदाहरणों को बढ़ावा देता है और समस्याओं को कम करने के लिए कैसे।

http://www.amazon.com/Taming-Java-Threads-Allen-Holub/dp/1893115100 http://www.holub.com/software/taming.java.threads.html

प्यार वहाँ अंत में खंड "यदि मैं राजा था"।

public final static void checkOnEventDispatchThread() { 
    if (!SwingUtilities.isEventDispatchThread()) { 
     throw new RuntimeException("This method can only be run on the EDT"); 
    } 
} 

हर विधि में यह कॉल आप लिखते हैं कि घटना प्रेषण धागे पर होना आवश्यक है:

4

पदार्थ की तरह बुद्धिमान खाल का उपयोग कर के लिए एक वैकल्पिक निम्नलिखित उपयोगिता विधि बनाने के लिए है। इसका एक फायदा सिस्टम चौड़े चेक को बहुत तेज़ी से अक्षम और सक्षम करना होगा, उदाहरण के लिए संभवतः इसे उत्पादन में हटा देना।

नोट बुद्धिमान खाल निश्चित रूप से अतिरिक्त कवरेज प्रदान कर सकते हैं।

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