2009-06-11 8 views
10

मेरी जावा परियोजना में, मैंने लिखा है कि लगभग हर गैर स्थैतिक विधि synchronized है। मैंने synchronized कीवर्ड को हटाकर आज कुछ कोड ठीक करने का निर्णय लिया है। वहीं वहां मैंने कई थ्रेडिंग मुद्दों को बनाया जो प्रदर्शन में कोई वृद्धि के साथ ठीक करने में काफी समय लगा। अंत में मैंने सबकुछ वापस कर दिया।हर जगह 'सिंक्रनाइज़' कीवर्ड को थप्पड़ मारने का कोई कारण नहीं है?

मुझे हर जगह "synchronized" के साथ कोड लिखने वाला कोई और नहीं दिखाई देता है। तो क्या कोई कारण है कि नहीं होना चाहिए "synchronized" हर जगह?

क्या होगा यदि मुझे प्रदर्शन के बारे में बहुत अधिक परवाह नहीं है (यानी विधि को हर कुछ सेकंड में एक से अधिक बार नहीं कहा जाता है)?

+13

इसी कारण से वे ब्लैक बॉक्स सामग्री से विमान नहीं बनाते हैं ... –

उत्तर

26

बेशक - प्रदर्शन। मॉनीटर की लागत है।

उत्तर न तो हटा रहा है और न ही यादृच्छिक फैशन में सिंक्रनाइज़ेशन जोड़ रहा है। ब्रायन गोएट्ज़ की "जावा कंसुरेंसी इन प्रैक्टिस" या डौग ली की "जावा थ्रेड्स" किताबों जैसे कुछ ठीक से इसे कैसे किया जाए, इसे पढ़ने के लिए बेहतर है। और बिल्कुल नए समवर्ती पैकेज सीखें।

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

+4

सिंक्रनाइज़ेशन की लागत की तुलना में बहुत बड़ी चिंताएं हैं। – Eddie

+11

बड़ी चिंताओं जैसे सिंक्रनाइज़ किए गए कीवर्ड को वास्तव में समझने के बिना तरीकों से जोड़ना, या यह क्या करता है। मैं इसके बारे में चिंता करता हूँ। – izb

+4

प्लस: सिंक्रनाइज़ की अनुचित ओवर-डोस मृत-ताले के कारण हो सकती है – Dirk

2

बस यह निश्चित रूप से चीजों को धीमा कर देगा।

प्रत्येक सिंक'एड ऑब्जेक्ट को यह सुनिश्चित करने के लिए किसी प्रकार का चेक करना होगा कि यह पहले से उपयोग में नहीं है और फिर उपयोग किए जाने पर झंडे सेट करें और समाप्त होने पर उन्हें रीसेट करें।

इसमें समय लगता है। आप शायद एक कार्यात्मक परिवर्तन नहीं देखेंगे, लेकिन यदि प्रदर्शन महत्वपूर्ण है, तो आपको देखना होगा।

7

प्रदर्शन बिंदु पहले से ही कहा जा चुका है।

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

+0

मैं बिल्कुल यह कहने जा रहा था। –

36

यदि आप अंधाधुंध रूप से सिंक्रनाइज़ करते हैं, तो आप deadlock बनाने का जोखिम भी चलाते हैं।

मान लीजिए कि मेरे पास दो कक्षाएं हैं, Foo और Bar, दोनों सिंक्रनाइज़ विधि doSomething() हैं। मान लें कि प्रत्येक वर्ग में एक सिंक्रनाइज़ विधि है जो पैरामीटर के रूप में अन्य वर्ग का उदाहरण लेती है।

public class Foo { 

    synchronized void doSomething() { 
     //code to doSomething 
    } 

    synchronized void doSomethingWithBar(Bar b) { 
     b.doSomething(); 
    } 

} 

public class Bar { 

    synchronized void doSomething() { 
     //code to doSomething 
    } 

    synchronized void doSomethingWithFoo(Foo f) { 
     f.doSomething(); 
    } 
} 

आप देख सकते हैं कि यदि आप Foo का एक उदाहरण और Bar का एक उदाहरण है, दोनों एक ही समय में एक दूसरे पर उनके doSomethingWith* तरीकों पर अमल करने की कोशिश कर रहा है, एक गतिरोध हो सकता है।

गतिरोध के लिए मजबूर करने के लिए, आप दोनों doSomethingWith* विधियों (उदाहरण के रूप में Foo का उपयोग कर) में एक नींद डाल सकता है:

synchronized void doSomethingWithBar(Bar b) { 
    try { 
     Thread.sleep(10000); 
    } catch (InterruptedException ie) { 
     ie.printStackTrace(); 
    } 

    b.doSomething(); 
} 

आपका मुख्य विधि में, आप उदाहरण के पूरा करने के लिए दो धागे शुरू:

public static void main(String[] args) { 
    final Foo f = new Foo(); 
    final Bar b = new Bar(); 
    new Thread(new Runnable() { 
     public void run() { 
      f.doSomethingWithBar(b); 
     } 
    }).start(); 

    new Thread(new Runnable() { 
     public void run() { 
      b.doSomethingWithFoo(f); 
     } 
    }).start(); 
} 
+4

यहां तक ​​कि डेडलॉक्स के बिना भी आप बड़ी परेशानी में पड़ सकते हैं। मुझे बस एक सिंक्रनाइज़ ब्लॉक के अंदर एक I/O ऑपरेशन द्वारा मारा गया है जिसे सप्ताह में हजारों बार कहा जाता है और लगभग 20 मिलीसेकंड लेता है। कोई परेशानी नहीं। लेकिन फिर कुछ अजीब कारणों से सप्ताह में दो बार इसमें 30 मिनट लगते हैं। आउच! –

12

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

थ्रेडिंग मास्टर के लिए एक अविश्वसनीय रूप से कठिन विषय है और यह समझना वाकई महत्वपूर्ण है कि आप चीजें क्यों कर रहे हैं। अन्यथा आप बहुत सारे कोड के साथ काम करेंगे जो डिजाइन के बजाए दुर्घटना से काम करता है। यह आपको दर्द का कारण बन जाएगा।

+6

या बेहतर अभी तक, धागे का उपयोग न करें जबतक कि आप बिल्कुल, सकारात्मक रूप से नहीं हैं! –

6

synchronized डालने से कहीं बेहतर है, हर जगह आपके वर्गों की ज़रूरतों के बारे में सावधानीपूर्वक कारण है, फिर उन आविष्कारों को सुनिश्चित करने के लिए पर्याप्त सिंक्रनाइज़ करें।

  1. गतिरोध
  2. जीवंतता समस्याओं

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

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

public class SimpleClass { 
    private volatile int min, max; 
    private volatile Date startTime; 
    // Assume there are many other class members 

    public SimpleClass(final int min, final int max) { 
     this.min = min; 
     this.max = max; 
    } 
    public void setMin(final int min) { 
     // set min and verify that min <= max 
    } 
    public void setMax(final int max) { 
     // set max and verify that min <= max 
    } 
    public Date getStartTime() { 
     return startTime; 
    } 
} 
ऊपर वर्ग के साथ

, जब मिनट या अधिकतम सेट करते समय आप सिंक्रनाइज़ करने के लिए की जरूरत है। उपरोक्त कोड टूटा हुआ है। इस वर्ग में क्या आविष्कार है? आपको यह सुनिश्चित करना होगा कि min <= max हर समय, जब भी कई थ्रेड setMin या setMax पर कॉल कर रहे हों।

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

1

मान लें कि आप इस उदाहरण

 

synchronized (lock){ 
    doSomething(); 
} 
 

है आप कई धागे बंद कर दिया है, तो आप उन्हें बाधित नहीं कर सकते हैं। लॉक ऑब्जेक्ट्स को "सिंक्रनाइज़" की बजाय लॉक करना बेहतर है क्योंकि आपके पास इंटरप्ट्स का बेहतर नियंत्रण हो सकता है। बेशक सभी सुझाव दिए गए हैं कि "सिंक्रनाइज़ किए गए" के साथ कुछ प्रदर्शन समस्याएं भी हैं और यदि आप उन्हें अधिक उपयोग करते हैं तो आपके पास डेडलॉक्स, livelocks, आदि हो सकता है

2

आपको नहीं करना चाहिए, और आपको शायद अपने डिज़ाइन पर पुनर्विचार करने की आवश्यकता है। मेरे अनुभव से, इस स्तर पर सिंक्रनाइज़ेशन सिर्फ स्केलेबल नहीं है। यह आपकी तत्काल समस्याओं को ठीक कर सकता है, लेकिन आपकी समग्र एप्लिकेशन अखंडता को ठीक करने में मदद नहीं करेगा।

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

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

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

0

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

अपने आप से पूछें, आप एक से अधिक धागे का उपयोग क्यों कर रहे हैं?

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