'सिंक्रोनाइज़ ’का क्या अर्थ है?


993

मेरे पास synchronizedकीवर्ड के उपयोग और महत्व के बारे में कुछ प्रश्न हैं ।

  • synchronizedकीवर्ड का महत्व क्या है ?
  • विधियाँ कब होनी चाहिए synchronized?
  • इसका प्रोग्राम और तार्किक रूप से क्या मतलब है?




1
मैं पहली टिप्पणी से पूरे प्रलेखन लिंक के माध्यम से चला गया, और जब तक मुझे अंतिम पैराग्राफ नहीं मिला, तब तक समझ में नहीं आया। लिंक चिपकाने और कुछ भी उद्धृत करने के बजाय, लिंक चिपकाना और एक उद्धरण जोड़ना अधिक उपयोगी हो सकता है।
रकीब

जवाबों:


878

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

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

एक बहुत, बहुत छोटे संक्षेप में: जब आपके पास दो धागे होते हैं जो एक ही 'संसाधन' को पढ़ और लिख रहे होते हैं foo, तो नाम वाले एक चर कहते हैं , आपको यह सुनिश्चित करने की आवश्यकता है कि ये धागे एक परमाणु तरीके से चर तक पहुंचते हैं। synchronizedकीवर्ड के बिना , आपका थ्रेड 1 परिवर्तन थ्रेड 2 से बना fooया खराब नहीं देख सकता है, यह केवल आधा बदला जा सकता है। यह वह नहीं होगा जो आप तार्किक रूप से उम्मीद करते हैं।

फिर, यह जावा में एक गैर-तुच्छ विषय है। अधिक जानने के लिए, SO और इंटरवेब के बारे में यहां विषयों का पता लगाएं:

इन विषयों की खोज तब तक करते रहें जब तक कि "ब्रायन गोएत्ज़" नाम स्थायी रूप से आपके मस्तिष्क में शब्द "संगामिति" से न जुड़ जाए ।


71
तो, मूल रूप से यह सिंक्रोनाइज़्ड कीवर्ड आपके तरीकों को सुरक्षित बनाता है?
रिगो विड्स

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

28
जब तक आप ब्रायन गोएट्ज़ (या शायद जॉन स्कीट) हैं, तब तक केवल भाषा की प्राथमिकताओं (सिंक्रनाइज़, अस्थिर) के साथ जावा समरूपता प्राप्त करना लगभग असंभव है। शुरुआत के लिए, java.util.concurrent पैकेज का उपयोग करें और उसके ऊपर निर्माण करें।
थिलो जूल

12
अधिक स्पष्ट रूप से: कई थ्रेड्स से एक ही समय में सिंक्रनाइज़ किए गए तरीके नहीं कहे जा सकते।
पीटर - मोनिका

2
@peterh सिंक्रनाइज़ इससे अधिक है, इसलिए अधिक क्रिया स्पष्टीकरण
स्टु थॉम्पसन

293

ठीक है, मुझे लगता है कि हमारे पास पर्याप्त सैद्धांतिक व्याख्याएं थीं, इसलिए इस कोड पर विचार करें

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

नोट: synchronizedअगले थ्रेड के कॉल टू मेथड टेस्ट () को तब तक रोकते हैं जब तक कि पिछले थ्रेड का निष्पादन समाप्त नहीं हो जाता। थ्रेड्स इस विधि को एक बार में एक्सेस कर सकते हैं। बिना synchronizedसभी धागे एक साथ इस विधि का उपयोग कर सकते हैं।

जब कोई थ्रेड ऑब्जेक्ट की सिंक्रोनाइज़्ड विधि 'टेस्ट' को बुलाता है (यहाँ ऑब्जेक्ट 'TheDemo' क्लास का एक उदाहरण है) यह उस ऑब्जेक्ट के लॉक को प्राप्त करता है, कोई भी नया थ्रेड उसी ऑब्जेक्ट के किसी भी सिंक्रोनाइज़ किए हुए तरीके को पिछले थ्रेड के रूप में नहीं कह सकता है। जिसने ताला प्राप्त कर लिया था वह ताला जारी नहीं करता है।

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

सिंक्रनाइज़ के साथ आउटपुट

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

आउटपुट बिना सिंक्रनाइज़ किए गए

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

7
महान उदाहरण, सिद्धांत को जानना अच्छा है, लेकिन कोड हमेशा अधिक विशिष्ट और पूर्ण होता है।
सेंटी इग्लेसियस

2
@ संतिलगियास "पूरा"? नहीं। यह उदाहरण लॉकिंग व्यवहार को दर्शाता है synchronized, लेकिन मेमोरी संगतता को अनदेखा किया जाता है।
स्टु थॉम्पसन

2
@Stu थॉम्पसन मेमोरी स्थिरता लॉकिंग का परिणाम है
धीरज सचान

@DheerajSachan उस तर्क के द्वारा फिर एक ReentrantLock का उपयोग करके यह स्मृति स्थिरता का परिणाम देगा। यह नहीं है
स्टु थॉम्पसन

3
@boltup_im_coding: प्रारंभ () विधि थ्रेड को "RUNNABLE" स्थिति में रखती है, जिसका अर्थ है कि यह निष्पादन के लिए तैयार है या पहले से ही निष्पादित हो रहा है। ऐसा हो सकता है कि रननेबल राज्य में एक और धागा (आमतौर पर जरूरी नहीं कि उच्च प्राथमिकता के साथ) कतार में कूदता है और निष्पादित करना शुरू कर देता है। उपरोक्त उदाहरण में, THREAD 3 THREAD 2 से पहले CPU प्राप्त करने के लिए हुआ
साहिल J

116

synchronizedकीवर्ड एक से अधिक थ्रेड से कोड या वस्तु के एक ब्लॉक को समवर्ती पहुँच रोकता है। के सभी तरीके Hashtableहैं synchronized, इसलिए केवल एक धागा उनमें से किसी को भी एक समय में निष्पादित कर सकता है।

synchronizedजैसे गैर- निर्माण का उपयोग करते समय HashMap, आपको निरंतरता त्रुटियों को रोकने के लिए अपने कोड में थ्रेड-सेफ्टी फीचर्स का निर्माण करना चाहिए।


81

synchronizedइसका मतलब है कि एक बहु थ्रेडेड वातावरण में, एक ऑब्जेक्ट synchronizedविधि (एस) / ब्लॉक (ओं) synchronizedको एक ही समय में कोड के विधि (एस) / ब्लॉक (एस) तक पहुंचने के लिए दो धागे नहीं होने देता है । इसका मतलब यह है कि एक धागा पढ़ नहीं सकता है जबकि दूसरा धागा इसे अपडेट करता है।

इसके बजाय दूसरा धागा तब तक इंतजार करेगा जब तक कि पहला धागा अपना निष्पादन पूरा नहीं कर लेता। ओवरहेड गति है, लेकिन लाभ डेटा की स्थिरता की गारंटी है।

यदि आपका आवेदन सिंगल थ्रेडेड है, लेकिन synchronizedब्लॉक लाभ प्रदान नहीं करता है।


54

synchronizedकीवर्ड जब विधि में प्रवेश एक ताला प्राप्त करने के लिए है, इसलिए है कि केवल एक धागा एक ही समय में विधि निष्पादित कर सकते हैं (दिए गए वस्तु उदाहरण के लिए, जब तक यह एक स्थिर तरीका है) एक धागे का कारण बनता है।

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

इस पर विचार करो:

 if (vector.isEmpty()){
     vector.add(data);
 }

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

इसलिए वास्तव में, आपको अपने एप्लिकेशन कोड में भी सिंक्रनाइज़ करना होगा।

क्योंकि विधि-स्तरीय सिंक्रनाइज़ेशन a) महंगा है, जब आपको इसकी आवश्यकता नहीं है और b) अपर्याप्त है जब आपको सिंक्रनाइज़ेशन की आवश्यकता होती है, तो अब अन-सिंक्रोनाइज़्ड रिप्लेसमेंट (वेक्टर के मामले में ArrayList) हैं।

अभी हाल ही में, संगामिति पैकेज जारी किया गया है, जिसमें कई चतुर उपयोगिताओं के साथ मल्टी-थ्रेडिंग मुद्दों का ध्यान रखा गया है।


26

अवलोकन

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

सिंक्रनाइज़ किए गए कीवर्ड का उपयोग कोड के एक ब्लॉक को परिभाषित करने के लिए किया जाता है जहां कई धागे एक ही चर को सुरक्षित तरीके से एक्सेस कर सकते हैं।

और गहरा

सिंटैक्स-वार synchronizedकीवर्ड एक Objectपैरामीटर के रूप में लेता है (जिसे लॉक ऑब्जेक्ट कहा जाता है ), जिसे बाद में ए { block of code }

  • जब निष्पादन इस कीवर्ड का सामना करता है, तो वर्तमान थ्रेड लॉक ऑब्जेक्ट को "लॉक / अधिग्रहित / लेने" (आपकी पिक लेने) की कोशिश करता है और लॉक प्राप्त होने के बाद संबंधित ब्लॉक के कोड को निष्पादित करता है।

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

  • एक समय में केवल एक धागा ही लॉक को पकड़ सकता है, उस समय के दौरान एक ही लॉक ऑब्जेक्ट को प्राप्त करने की कोशिश करने वाले अन्य सभी धागे प्रतीक्षा करेंगे ( किसी भी निष्पादन को रोकें)। लॉक तब रिलीज़ होगा जब निष्पादन सिंक्रनाइज़ कोड ब्लॉक से बाहर निकलता है।

सिंक्रनाइज़ किए गए तरीके:

synchronizedएक विधि परिभाषा में कीवर्ड जोड़ना लॉक ऑब्जेक्ट जा रहा है this (उदाहरण के तरीकों के लिए) और ClassInQuestion.getClass() (वर्ग विधियों के लिए ) के साथ एक सिंक्रनाइज़ कोड ब्लॉक में लिपटे जा रहे पूरे विधि निकाय के बराबर है ।

- इंस्टेंट विधि एक ऐसी विधि है जिसमें staticकीवर्ड नहीं होता है ।
- क्लास मेथड एक ऐसी विधि है जिसमें staticकीवर्ड होता है।

तकनीकी

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

एक थ्रेड (दीवार-घड़ी का समय) से पहले एक थ्रेड ऑपरेशन में इसे पूरा करने के लिए पर्याप्त नहीं है, एक अन्य थ्रेड इसे पढ़ता है, क्योंकि हार्डवेयर चर के मूल्य को कैश कर सकता था, और रीडिंग थ्रेड को कैश्ड मान के बजाय जो लिखा गया था वह दिखाई देगा यह।

निष्कर्ष

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

सूत्रों का कहना है

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Java® भाषा विशिष्टता, 2015-02-13


क्षमा करें, लेकिन मेरे पास यह उदाहरण है और मुझे इसका अर्थ समझ में नहीं आता: `पूर्णांक i1 = Arrays.asList (1,2,3,4,5) .stream ()। FindAny ()। Get (); सिंक्रोनाइज़ (i1) {Integer i2 = Arrays.asList (6,7,8,9,10)। समानांतर समानांतर () .sorted () .findAny ()। get (); System.out.println (i1 + "" + i2); } `1. आपने पहली बार ब्लॉक को क्यों लागू किया और इस आह्वान का कोड पर कोई प्रभाव नहीं पड़ा? 2. पहले पर ब्लॉक के आह्वान के बावजूद दूसरा उदाहरण थ्रेड-सुरक्षित होगा?
Adrr83

1
@ Adryr83 यदि आपका कोई प्रश्न है, तो आप शायद एक नया प्रश्न पोस्ट करके पूछ सकते हैं। लेकिन जब से हम यहाँ हैं, मैं वह करूँगा जो मैं कर सकता हूँ (आपका सवाल समझना थोड़ा मुश्किल है)। कोड के उस टुकड़े के बारे में मैं जो कुछ बता सकता हूं, उसमें ऐसा कुछ भी नहीं है जिसमें सिंक्रोनाइजेशन की जरूरत हो। यह संदर्भ से बाहर है। सुझाव: यदि आप कर सकते हैं, तो कोड को छोटे अलग-अलग टुकड़ों में विभाजित करने का प्रयास करें, और फिर उन लोगों के बारे में जवाब खोजें। कोड के एक बड़े ब्लॉक का पता लगाने की तुलना में, छोटी और अलग-थलग समस्याओं को समझने में बहुत आसान है।
गीमा २

21

इसे एक तरह का टर्नस्टाइल समझें, जैसा कि आप फुटबॉल ग्राउंड में देख सकते हैं। वहाँ लोगों के समानांतर स्टीम प्राप्त करना चाहते हैं, लेकिन टर्नस्टाइल में वे 'सिंक्रनाइज़' हैं। एक समय में केवल एक व्यक्ति के माध्यम से प्राप्त कर सकते हैं। उन सभी के माध्यम से प्राप्त करना चाहते हैं, लेकिन उन्हें इंतजार करना पड़ सकता है।


16

सिंक्रनाइज़ कीवर्ड क्या है?

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

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

तरीके कब सिंक्रनाइज़ किए जाते हैं?

जब आप synchronizedविधि परिभाषा या घोषणा में जोड़ते हैं तो विधियाँ सिंक्रनाइज़ की जाती हैं । आप एक विधि के साथ कोड के एक विशेष ब्लॉक को भी सिंक्रनाइज़ कर सकते हैं।

इसका क्या मतलब है कि व्याकरणिक और तार्किक रूप से समर्थक?

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

यह एक जादू के साथ नहीं किया जा सकता है। यह प्रोग्रामर की जिम्मेदारी है कि वह आवेदन में महत्वपूर्ण सेक्शन (वर्गों) की पहचान करे और उसके अनुसार उसकी सुरक्षा करे। जावा आपके आवेदन की सुरक्षा के लिए एक ढांचा प्रदान करता है, लेकिन कहाँ और क्या सभी वर्गों की रक्षा करना प्रोग्रामर की जिम्मेदारी है।

जावा प्रलेखन पृष्ठ से अधिक जानकारी

आंतरिक ताले और तुल्यकालन:

आंतरिक आंतरिक लॉक या मॉनिटर लॉक के रूप में जानी जाने वाली आंतरिक इकाई के आसपास सिंक्रोनाइज़ेशन का निर्माण किया जाता है। आंतरिक ताले तुल्यकालन के दोनों पहलुओं में एक भूमिका निभाते हैं: किसी वस्तु की स्थिति के लिए विशेष पहुंच को लागू करना और ऐसा होना-पहले संबंधों को स्थापित करना जो दृश्यता के लिए आवश्यक हैं।

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

यह कहा जाता है कि लॉक को प्राप्त करने और लॉक जारी करने के बीच के समय में एक धागे को आंतरिक लॉक कहा जाता है। जब तक एक धागा एक आंतरिक लॉक का मालिक होता है, कोई भी अन्य धागा एक ही लॉक का अधिग्रहण नहीं कर सकता है। जब वह ताला प्राप्त करने का प्रयास करेगा तो दूसरा धागा अवरुद्ध हो जाएगा।

जब कोई थ्रेड आंतरिक लॉक जारी करता है, तो उस एक्शन और उसी लॉक के किसी भी बाद के अधिग्रहण के बीच एक होने से पहले संबंध स्थापित होता है।

सिंक्रनाइज़ किए जा रहे तरीकों के दो प्रभाव हैं :

सबसे पहले, एक ही वस्तु पर इंटरलेव करने के लिए सिंक्रनाइज़ किए गए तरीकों के दो आह्वान संभव नहीं है।

जब कोई थ्रेड किसी ऑब्जेक्ट के लिए एक सिंक्रोनाइज़ की गई विधि को निष्पादित कर रहा होता है, तो अन्य सभी थ्रेड्स जो ऑब्जेक्ट के साथ पहले थ्रेड को निष्पादित करने तक एक ही ऑब्जेक्ट ब्लॉक (सस्पेंड निष्पादन) के लिए सिंक्रनाइज़ किए गए तरीकों को लागू करते हैं।

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

यह गारंटी देता है कि ऑब्जेक्ट की स्थिति में परिवर्तन सभी थ्रेड्स को दिखाई देते हैं।

सिंक्रनाइज़ेशन के अन्य विकल्पों की तलाश करें:

जावा में सिंक्रनाइज़ (यह) से बचें?


11

Synchronized normal methodसमतुल्य Synchronized statement(इसका उपयोग करें)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static methodसमतुल्य Synchronized statement(उपयोग वर्ग)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

सिंक्रोनाइज़्ड स्टेटमेंट (वेरिएबल का उपयोग करके)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

के लिए synchronized, हम दोनों Synchronized Methodsऔर है Synchronized Statements। हालाँकि, Synchronized Methodsइसके समान Synchronized Statementsही हमें समझने की आवश्यकता है Synchronized Statements

=> मूल रूप से, हमारे पास होगा

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

यहां 2 विचार हैं जो समझने में मदद करते हैं synchronized

  • हर वस्तु / वर्ग का इससे intrinsic lockजुड़ाव होता है।
  • जब कोई थ्रेड एक आह्वान करता है synchronized statement, तो यह स्वचालित रूप से intrinsic lockउस synchronized statement'sऑब्जेक्ट के लिए प्राप्त करता है और विधि के वापस आने पर इसे जारी करता है। जब तक एक धागा का मालिक है intrinsic lock, कोई अन्य धागा SAME लॉक => थ्रेड सुरक्षित प्राप्त नहीं कर सकता है ।

=> जब एक thread Aचालान synchronized(this){// code 1}=> सभी ब्लॉक कोड (वर्ग के अंदर) जहां है synchronized(this)और सभी synchronized normal method(वर्ग के अंदर) लॉक है क्योंकि SAME लॉक है। यह thread Aअनलॉक ("// कोड 1" समाप्त) के बाद निष्पादित होगा ।

यह व्यवहार synchronized(a variable){// code 1}या के समान है synchronized(class)

एक ही ताला => ताला (किस विधि पर निर्भर नहीं है? या कौन सा बयान?)

सिंक्रनाइज़ विधि या सिंक्रनाइज़ स्टेटमेंट का उपयोग करें?

मैं पसंद करता हूं synchronized statementsक्योंकि यह अधिक विस्तार योग्य है। उदाहरण, भविष्य में, आपको केवल विधि के एक भाग को सिंक्रनाइज़ करने की आवश्यकता है। उदाहरण के लिए, आपके पास 2 सिंक्रनाइज़ विधि है और यह एक दूसरे के लिए प्रासंगिक नहीं है , हालांकि जब कोई थ्रेड विधि चलाता है, तो यह अन्य विधि को ब्लॉक कर देगा (यह उपयोग द्वारा रोका जा सकता है synchronized(a variable))।

हालाँकि, सिंक्रोनाइज़ किया हुआ तरीका सरल है और कोड सरल दिखता है। कुछ वर्ग के लिए, एक दूसरे से संबंधित कक्षा में केवल 1 सिंक्रोनाइज़ की गई विधि, या सभी सिंक्रनाइज़ किए गए तरीके => हम synchronized methodकोड को छोटा और समझने में आसान बनाने के लिए उपयोग कर सकते हैं

ध्यान दें

(यह करने के लिए प्रासंगिक नहीं है synchronized, यह वस्तु और वर्ग या कोई भी स्थिर और स्थिर के बीच अलग है)।

  • आप का उपयोग करते हैं synchronizedया सामान्य विधि या synchronized(this)या synchronized(non-static variable)यह प्रत्येक वस्तु के उदाहरण के आधार पर सिंक्रनाइज़ होगा।
  • आप का उपयोग करते हैं synchronizedया स्थिर विधि या synchronized(class)या synchronized(static variable)यह वर्ग के आधार पर सिंक्रनाइज़ होगा

संदर्भ

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

आशा है कि यह मदद करेगा


11

यहाँ जावा ट्यूटोरियल से एक स्पष्टीकरण है ।

निम्नलिखित कोड पर विचार करें:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

यदि countइसका उदाहरण है SynchronizedCounter, तो इन विधियों को सिंक्रनाइज़ करने के दो प्रभाव हैं:

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

9

मेरी समझ के लिए मूल रूप से सिंक्रोनाइज़ करने का मतलब है कि कंपाइलर आपके तरीके के आसपास एक मॉनिटर.इंटरनेट और मॉनिटर.एक्सिट लिखें। जैसे कि यह थ्रेड सुरक्षित हो सकता है कि इसका उपयोग किस प्रकार किया जाता है (मेरा मतलब है कि आप सिंक्रनाइज़ किए गए तरीकों से एक ऑब्जेक्ट लिख सकते हैं जो आपके वर्ग के अनुसार थ्रेडसेफ़ नहीं है)।


5

अन्य उत्तर गायब हैं एक महत्वपूर्ण पहलू है: मेमोरी बाधाएं । थ्रेड सिंक्रोनाइज़ेशन में मूल रूप से दो भाग होते हैं : क्रमांकन और दृश्यता। मैं हर किसी को "jvm मेमोरी बैरियर" के लिए Google को सलाह देता हूं, क्योंकि यह एक गैर-तुच्छ और अत्यंत महत्वपूर्ण विषय है (यदि आप कई थ्रेड द्वारा एक्सेस किए गए साझा किए गए डेटा को संशोधित करते हैं)। ऐसा करने के बाद, मैं java.util.concurrent पैकेज की कक्षाओं को देखने की सलाह देता हूं जो स्पष्ट सिंक्रनाइज़ेशन का उपयोग करने से बचने में मदद करती हैं, जो बदले में कार्यक्रमों को सरल और कुशल रखने में मदद करती हैं, शायद गतिरोध को भी रोकती हैं।

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

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

मेमोरी संगति प्रभाव: अन्य समवर्ती संग्रहों के साथ, एक वस्तु में एक वस्तु को रखने से पहले एक थ्रेड में क्रियाएँ एक समवर्तीलिंक में घटित होती हैं , दूसरे सूत्र में उस तत्व की पहुँच या निष्कासन के बाद होने वाली क्रियाओं से पहले

यह निहित व्यवहार कुछ हद तक एक खतरनाक पहलू है क्योंकि ज्यादातर जावा प्रोग्रामर बिना ज्यादा अनुभव के सिर्फ इसलिए बहुत कुछ ले लेंगे जैसा कि दिया गया है। और फिर अचानक इस थ्रेड पर ठोकर खाने के बाद जावा ऐसा नहीं कर रहा है जो उत्पादन में ऐसा करने के लिए "माना जाता है" जहां एक अलग कार्य भार है - और यह संगामिति मुद्दों का परीक्षण करना बहुत कठिन है।


3

सिंक्रोनाइज्ड का सीधा सा मतलब है कि सिंगल थ्रेड से जुड़े कई थ्रेड्स गंदे पढ़ने और लिखने से रोक सकते हैं अगर सिंक्रोनाइज़्ड ब्लॉक का इस्तेमाल किसी खास ऑब्जेक्ट पर किया जाए। आपको और अधिक स्पष्टता प्रदान करने के लिए, एक उदाहरण दें:

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

हमने दो MyRunnable क्लास ऑब्जेक्ट बनाए हैं, runnable1 को थ्रेड 1 के साथ साझा किया जा रहा है और थ्रेड 3 और runnable2 को केवल थ्रेड 2 के साथ साझा किया जा रहा है। अब जब t1 और t3 का उपयोग बिना सिंक्रनाइज़ किए बिना शुरू होता है, तो PFB आउटपुट जो यह बताता है कि थ्रेड 1 और 3 दोनों एक साथ var value को प्रभावित करते हैं जहाँ थ्रेड 2 के लिए, var की अपनी मेमोरी है।

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

Synchronzied का उपयोग करते हुए, थ्रेड 3 सभी स्थितियों में पूर्ण होने के लिए थ्रेड 1 की प्रतीक्षा कर रहा है। अधिग्रहित किए गए दो ताले हैं, एक रननेबल 1 पर थ्रेड 1 और थ्रेड 3 द्वारा साझा किया गया है और दूसरा रननेबल 2 पर थ्रेड 2 द्वारा साझा किया गया है।

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

सिंक्रोनाइज्ड का मतलब इससे भी अधिक है: इसका मेमोरी बाधा पर गहरा प्रभाव पड़ता है।
user1050755

1

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

नोट दूसरा थ्रेड उसी ऑब्जेक्ट की विधि तक पहुँच सकता है जिसे सिंक्रनाइज़ नहीं किया गया है। एक थ्रेड लॉक को कॉल करके जारी कर सकता है

Object.wait()

0

synchronizedजावा में ब्लॉक मल्टीथ्रेडिंग में एक मॉनिटर है। synchronizedएक ही वस्तु / वर्ग के साथ ब्लॉक केवल एक धागे से निष्पादित किया जा सकता है, अन्य सभी इंतजार कर रहे हैं। यह race conditionस्थिति के साथ मदद कर सकता है जब कई धागे एक ही चर को अपडेट करने की कोशिश करते हैं (पहला चरण के बारे में उपयोग कर रहा हैvolatile )

Java 5synchronizedसमर्थन के द्वारा विस्तारित happens-before[के बारे में]

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

अगला कदम है java.util.concurrent

अस्थिर बनाम सिंक्रनाइज़


-6

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.