عند استخدام الكلمة الرئيسية لغة Java لتعديل طريقة أو كتلة رمز ، يمكن أن تضمن أن مؤشر ترابط واحد ينفذ رمز واحد في نفس الوقت.
1. عندما يصل اثنين من مؤشرات الترابط المتزامنة هذه كتلة الكود المتزامن (هذا) في نفس كائن الكائن ، يمكن تنفيذ مؤشر ترابط واحد فقط خلال فترة واحدة. يجب أن ينتظر مؤشر ترابط آخر حتى يقوم مؤشر الترابط الحالي بتنفيذ كتلة الرمز هذه قبل تنفيذ كتلة الكود.
2. ومع ذلك ، عندما يصل مؤشر ترابط واحد إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، لا يزال بإمكان مؤشر ترابط آخر الوصول إلى كتلة رمز التزامن غير المتزامنة (هذا) في هذا الكائن.
3. من الأهمية بمكان أنه عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، فإن مؤشرات الترابط الأخرى ستحظر الوصول إلى جميع كتل رمز التزامن (هذا) متزامنة أخرى في الكائن.
4. ينطبق المثال الثالث أيضًا على كتل التعليمات البرمجية المتزامنة الأخرى. أي عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن لكائن ، فإنه يحصل على قفل كائن هذا الكائن. نتيجة لذلك ، يتم حظر مؤشرات الترابط الأخرى إلى جميع أجزاء الكود المتزامن لكائن الكائن مؤقتًا.
5. تنطبق القواعد أعلاه أيضًا على أقفال الكائنات الأخرى.
إعطاء مثال:
1. عندما يصل اثنين من مؤشرات الترابط المتزامنة هذه كتلة الكود المتزامن (هذا) في نفس كائن الكائن ، يمكن تنفيذ مؤشر ترابط واحد فقط خلال فترة واحدة. يجب أن ينتظر مؤشر ترابط آخر حتى يقوم مؤشر الترابط الحالي بتنفيذ كتلة الرمز هذه قبل تنفيذ كتلة الكود.
Package ths ؛ public class thread1 تنفذ runnable {public void run () {synchronized (this) {for (int i = 0 ؛ i <5 ؛ i ++) {system.out.println (thread.currentThread (). getName () + "حلقة متزامنة" + i) ؛ }}} public static void main (string [] args) {thread1 t1 = new thread1 () ؛ الموضوع TA = موضوع جديد (T1 ، "A") ؛ THELL TB = موضوع جديد (T1 ، "B") ؛ ta.start () ؛ tb.start () ؛ }}نتيجة:
حلقة متزامنة 0
حلقة متزامنة 1
حلقة متزامنة 2
حلقة متزامنة 3
حلقة متزامنة 4
ب حلقة متزامنة 0
ب حلقة متزامنة 1
ب حلقة متزامنة 2
ب حلقة متزامنة 3
ب حلقة متزامنة 4
2. ومع ذلك ، عندما يصل مؤشر ترابط واحد إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، لا يزال بإمكان مؤشر ترابط آخر الوصول إلى كتلة رمز التزامن غير المتزامنة (هذا) في هذا الكائن.
حزمة ths ؛ public class thread2 {public void m4t1 () {synchronized (this) {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ":" + i) ؛ حاول {thread.sleep (500) ؛ } catch (interruptedException ie) {}}}} public void m4t2 () {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ":" + i) ؛ حاول {thread.sleep (500) ؛ } catch (interruptedException ie) {}}} public static void main (string [] args) {Final Thread2 myt2 = new thread2 () ؛ Thread T1 = New Thread (New RunNable () {public void run () {myt2.m4t1 () ؛}} ، "T1") ؛ Thread T2 = New Thread (New RunNable () {public void run () {myt2.m4t2 () ؛}} ، "T2") ؛ t1.start () ؛ t2.start () ؛ }} نتيجة:
T1: 4
T2: 4
T1: 3
T2: 3
T1: 2
T2: 2
T1: 1
T2: 1
T1: 0
T2: 0
3. من الأهمية بمكان أنه عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، فإن مؤشرات الترابط الأخرى ستحظر الوصول إلى جميع كتل رمز التزامن (هذا) متزامنة أخرى في الكائن.
// تعديل thread2.m4t2 () الطريقة: public void m4t2 () {synchronized (this) {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ":" + i) ؛ حاول {thread.sleep (500) ؛ } catch (InterruptedException IE) {}}}}نتيجة:
T1: 4
T1: 3
T1: 2
T1: 1
T1: 0
T2: 4
T2: 3
T2: 2
T2: 1
T2: 0
4. ينطبق المثال الثالث أيضًا على كتل التعليمات البرمجية المتزامنة الأخرى. أي عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن لكائن ، فإنه يحصل على قفل كائن هذا الكائن. نتيجة لذلك ، يتم حظر مؤشرات الترابط الأخرى إلى جميع أجزاء الكود المتزامن لكائن الكائن مؤقتًا.
// تعديل طريقة thread2.m4t2 () على النحو التالي: void synchronized m4t2 () {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ":" + i) ؛ حاول {thread.sleep (500) ؛ } catch (InterruptedException IE) {}}} نتيجة:
T1: 4
T1: 3
T1: 2
T1: 1
T1: 0
T2: 4
T2: 3
T2: 2
T2: 1
T2: 0
5. تنطبق القواعد المذكورة أعلاه أيضًا على أقفال الكائن الأخرى:
حزمة ths ؛ public class thread3 {class inner {private void m4t1 () {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ": inner.m4t1 () =" + i) ؛ حاول {thread.sleep (500) ؛ } catch (interruptedException ie) {}}} private void m4t2 () {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ": inner.m4t2 () =" + i) ؛ حاول {thread.sleep (500) ؛ } catch (interruptedException ie) {}}}} private void m4t1 (Inner Inner) {synchronized (inner) {// استخدم كائن قفل inner.m4t1 () ؛ } private void m4t2 (inner inner) {inner.m4t2 () ؛ } public static void main (string [] args) {Final Thread3 myt3 = new thread3 () ؛ Inner Inner النهائي = myt3.new inner () ؛ Thread T1 = New Thread (New RunNable () {public void run () {myt3.m4t1 (inner) ؛}} ، "t1") ؛ Thread T2 = New Thread (New RunNable () {public void run () {myt3.m4t2 (inner) ؛}} ، "T2") ؛ t1.start () ؛ t2.start () ؛ }}نتيجة:
على الرغم من أن مؤشر الترابط T1 يحصل على قفل كائن على الداخلية ، نظرًا لأن مؤشر الترابط T2 يصل إلى الجزء غير المتزامن في نفس الداخلية. لذلك ، لا يتداخل الخيوطان مع بعضهما البعض.
T1: inner.m4t1 () = 4
T2: inner.m4t2 () = 4
T1: inner.m4t1 () = 3
T2: inner.m4t2 () = 3
T1: inner.m4t1 () = 2
T2: inner.m4t2 () = 2
T1: inner.m4t1 () = 1
T2: inner.m4t2 () = 1
T1: inner.m4t1 () = 0
T2: inner.m4t2 () = 0
الآن ضع المزامنة أمام inner.m4t2 ():
void m4t2 () {int i = 5 ؛ بينما (i--> 0) {system.out.println (thread.currentThread (). getName () + ": inner.m4t2 () =" + i) ؛ حاول {thread.sleep (500) ؛ } catch (InterruptedException IE) {}}}نتيجة:
على الرغم من أن المواضيع T1 و T2 تصل إلى جزأين غير ذوي صلة من نفس الكائن الداخلي ، لأن T1 يحصل أولاً على قفل الكائن إلى الداخلية ، يتم حظر وصول T2 إلى inner.m4t2 () أيضًا لأن M4T2 () طريقة تزامن في INNER.
T1: inner.m4t1 () = 4
T1: inner.m4t1 () = 3
T1: inner.m4t1 () = 2
T1: inner.m4t1 () = 1
T1: inner.m4t1 () = 0
T2: inner.m4t2 () = 4
T2: inner.m4t2 () = 3
T2: inner.m4t2 () = 2
T2: inner.m4t2 () = 1
T2: inner.m4t2 () = 0
المادة 2:
الكلمة الرئيسية المتزامنة ، والتي تتضمن استخدامين: الطريقة المتزامنة والكتلة المتزامنة.
1. الطريقة المتزامنة: أعلن الطريقة المتزامنة عن طريق إضافة الكلمة الرئيسية المتزامنة إلى إعلان الطريقة. يحب:
Accessval المتزامن العام (int newval) ؛
تتحكم الطريقة المتزامنة في الوصول إلى متغيرات عضو الفئة: كل مثيل فئة يتوافق مع قفل ، ويجب أن تحصل كل طريقة متزامنة على قفل مثيل الفئة الذي يستدعي الطريقة قبل تنفيذها. خلاف ذلك ، يتم حظر الخيط الذي ينتمي إليه. بمجرد تنفيذ الطريقة ، سوف تشغل القفل حصريًا. لن يتم إصدار القفل حتى يعود من الطريقة. يمكن للخيط المحظور الحصول على القفل وإعادة إدخال الحالة القابلة للتنفيذ. تضمن هذه الآلية أنه في الوقت نفسه ، لكل مثيل فئة ، على الأكثر واحدة من جميع وظائف الأعضاء المعلنة أن تزامنه في حالة قابلة للتنفيذ (لأنه على الأكثر يمكن الحصول على القفل المقابل لمثيل الفصل) ، وبالتالي تجنب تعارضات الوصول بفعالية لمتغيرات أعضاء الفصل (طالما أن جميع الأساليب الممكنة للوصول إلى متغيرات أعضاء الفئة ، يتم إعلان التزامن).
في Java ، ليس فقط مثيلات الفصل ، ولكن كل فصل يتوافق أيضًا مع القفل ، حتى نتمكن من إعلان وظيفة العضو الثابت للفئة على أنها متزامنة للتحكم في وصولها إلى متغيرات الأعضاء الثابتة في الفصل.
عيب الطريقة المتزامنة: الإعلان عن طريقة كبيرة كما متزامن سيؤثر بشكل كبير على الكفاءة. عادةً ، إذا تم الإعلان عن طريقة فئة مؤشر الترابط () على أنها متزامنة ، حيث تم تشغيلها طوال عمر الخيط ، فلن يتسبب ذلك أبدًا في أي طريقة متزامنة في هذه الفئة. بالطبع يمكننا حل هذه المشكلة عن طريق وضع الكود الذي يصل إلى متغيرات عضو الفصل إلى طريقة خاصة ، وإعلانها على أنها متزامنة ، ووصفها بالطريقة الرئيسية ، لكن Java توفر لنا حلًا أفضل ، أي الكتلة المتزامنة.
2. كتلة متزامنة: أعلن الكتلة المتزامنة من خلال الكلمة الرئيسية المتزامنة. بناء الجملة كما يلي:
متزامن (syncobject) {// الكود الذي يسمح بالتحكم في الوصول} الكتلة المتزامنة هي كتلة رمز يجب أن يحصل فيها الرمز على قفل لكائن Syncobject (كما ذكرنا سابقًا ، يمكن أن يكون مثيلًا أو فئة فئة) قبل تنفيذها. الآلية المحددة هي نفسها كما هو موضح أعلاه. نظرًا لأنه يمكن استهدافه في أي كتلة رمز ويمكن تحديد كائنات مغلقة في أي وقت ، فهي أكثر مرونة.
بعض فهم المتزامنة (هذا) <br /> 1. عندما يصل اثنين من مؤشرات الترابط المتزامنة إلى كتلة التعليمات البرمجية المتزامنة (هذا) في نفس الكائن ، يمكن تنفيذ مؤشر ترابط واحد فقط خلال فترة واحدة. يجب أن ينتظر مؤشر ترابط آخر حتى يقوم مؤشر الترابط الحالي بتنفيذ كتلة الرمز هذه قبل تنفيذ كتلة الكود.
2. ومع ذلك ، عندما يصل مؤشر ترابط واحد إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، لا يزال بإمكان مؤشر ترابط آخر الوصول إلى كتلة رمز التزامن غير المتزامنة (هذا) في هذا الكائن.
3. من الأهمية بمكان أنه عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن للكائن ، فإن مؤشرات الترابط الأخرى ستحظر الوصول إلى جميع كتل رمز التزامن (هذا) متزامنة أخرى في الكائن.
4. ينطبق المثال الثالث أيضًا على كتل التعليمات البرمجية المتزامنة الأخرى. أي عندما يصل مؤشر ترابط إلى كتلة رمز المزامنة (هذا) متزامن لكائن ، فإنه يحصل على قفل كائن هذا الكائن. نتيجة لذلك ، يتم حظر مؤشرات الترابط الأخرى إلى جميع أجزاء الكود المتزامن لكائن الكائن مؤقتًا.
5. تنطبق القواعد أعلاه أيضًا على أقفال الكائنات الأخرى.
كيفية استخدام المزامنة في جافا
على سبيل المثال: الكائن يشبه المنزل الكبير ، يكون الباب مفتوحًا دائمًا. هناك العديد من الغرف في المنزل (أي الطريقة).
هذه الغرف مقفلة (طريقة متزامنة) ، ولا يتم قفلها (الطريقة العادية). هناك مفتاح عند الباب ، والذي يمكنه فتح جميع الغرف المقفلة.
بالإضافة إلى ذلك ، أقارن جميع المواضيع التي ترغب في استدعاء طريقة الكائن بالأشخاص الذين يرغبون في الدخول إلى غرفة في هذا المنزل. لا يوجد سوى أشياء كثيرة ، دعنا نرى كيف تعمل هذه الأشياء.
هنا نوضح أولاً متطلباتنا المسبقة. يحتوي الكائن على طريقة متزامنة واحدة على الأقل ، وإلا ما هي الهدف من هذا المفتاح؟ بالطبع ، لن يكون هناك مثل هذا الموضوع بالنسبة لنا.
أراد رجل الدخول إلى غرفة مغلقة. جاء إلى باب المنزل ورأى المفتاح هناك (هذا يعني أنه لا أحد يريد استخدام الغرفة المقفلة حتى الآن). لذلك مشى وحصل على المفاتيح واستخدم الغرف كما خطط. كن على علم بأنه سيعود المفتاح فور استخدام الغرفة المقفلة في كل مرة. حتى لو أراد استخدام غرفتين مغلقتين على التوالي ، فسوف يعيد المفاتيح لاستردادهما. لذلك ، فإن مبدأ استخدام مفتاح في الحالات العادية هو: "الاقتراض كما تستخدمه ، وإعادته بمجرد استخدامه."
في هذا الوقت ، يمكن للأشخاص الآخرين استخدام تلك الغرف غير المؤمّنة دون قيود. يمكن لشخص واحد استخدام غرفة واحدة ، ويمكن لشخصين استخدام غرفة واحدة ، دون قيود. ولكن إذا أراد شخص ما الدخول إلى غرفة مغلقة ، فعليه الركض إلى البوابة لإلقاء نظرة. بالطبع ، إذا كان لديك المفتاح ، فستغادر. إذا لم يكن لديك ذلك ، فيمكنك الانتظار فقط. إذا كان الكثير من الناس ينتظرون هذا المفتاح ، فمن سيحصل على المفتاح أولاً بعد إرجاعه؟ غير مضمون. مثل الرجل في المثال السابق الذي أراد استخدام غرفتين مغلقتين على التوالي ، إذا كان هناك أشخاص آخرون ينتظرون المفاتيح في الوسط ، لم يكن هناك ما يضمن أن يحصل عليه هذا الرجل مرة أخرى. (تنص مواصفات Java بوضوح على أنه ليس مضمونًا في العديد من الأماكن ، مثل المدة التي يستغرقها الخيط. seleep () للعودة إلى الجري بعد الراحة ، يتم تنفيذ مؤشر الترابط بنفس الأولوية أولاً ، وأي موضوع في مجموعة الانتظار سيتم إعطاؤه الأولوية بعد أن يتم إصدار القفل ، وما إلى ذلك. حالة واحدة ، ولكن بناء على العديد من المقالات.
نظرًا لوجود الكثير من شروط الحكم ، إذا قلت ذلك ، فقد يؤثر ذلك على تعزيز Java ، أو قد يكون بسبب حماية الملكية الفكرية. أعطاني صن وعدًا ومرت به. لا حرج في ذلك. لكنني أعتقد أن أوجه عدم اليقين هذه ليست غير مؤكدة تمامًا. لأن الكمبيوتر نفسه يعمل وفقا للتعليمات. حتى لو كانت الظاهرة تبدو عشوائية ، فهي منتظمة بالفعل. يعرف أي شخص درس أجهزة الكمبيوتر أن الاسم العلمي للأرقام العشوائية في أجهزة الكمبيوتر هو أرقام عشوائية زائفة ، والتي يكتبها أشخاص يستخدمون طرقًا معينة ، ويبدو أنها عشوائية. بالإضافة إلى ذلك ، ربما يكون ذلك لأنه من الصعب للغاية التأكد من أنه ليس ذا معنى كبير ، لذلك إذا لم تكن متأكدًا ، فأنت لست متأكدًا. )
دعنا نلقي نظرة على كتلة رمز التزامن. هناك اختلاف طفيف من طريقة التزامن.
1. من حيث الحجم ، تكون كتلة رمز التزامن أصغر من طريقة التزامن. يمكنك التفكير في كتلة رمز التزامن كمساحة في غرفة مقفلة مفصولة بشاشة مغلقة.
2. يمكن أن تحدد كتلة رمز التزامن أيضًا مفتاح الحصول على كائن آخر معين. تمامًا مثل تحديد المفتاح لإلغاء قفل الشاشة ، يمكنك استخدام مفتاح هذه الغرفة ؛ يمكنك أيضًا تحديد أن مفتاح منزل آخر يمكنه فتحه. وبهذه الطريقة ، يجب عليك الركض إلى منزل آخر لإحضار هذا المفتاح واستخدام مفتاح ذلك المنزل لفتح الشاشة المقفلة لهذا المنزل.
تذكر أن مفتاح ذلك المنزل الآخر الذي حصلت عليه لا يؤثر على الآخرين الذين يدخلون الغرفة دون أقفال في هذا المنزل.
لماذا تستخدم كتل التعليمات البرمجية المتزامنة؟ أعتقد أنه يجب أن يكون هكذا: أولاً وقبل كل شيء ، يكون لجزء المزامنة من البرنامج تأثير كبير على كفاءة التشغيل ، وعادة ما تكون الطريقة هي إنشاء بعض المتغيرات المحلية أولاً ، ثم القيام ببعض العمليات على هذه المتغيرات ، مثل العمليات ، والعرض ، وما إلى ذلك ؛ والمزيد من التعليمات البرمجية التي تغطيها التزامن ، كلما كان التأثير على الكفاءة أكثر خطورة. لذلك ، نحاول عادة تضييق تأثيره.
كيف تفعل ذلك؟ مزامنة كتل الكود. نحن فقط نزامن أماكن التزامن بطريقة واحدة ، مثل العمليات.
بالإضافة إلى ذلك ، فإن ميزة كتل التعليمات البرمجية المتزامنة التي يمكنها تحديد Keys لها ميزة إضافية ، وهي أنه يمكن أن تشغل مفاتيح كائن ما في غضون فترة زمنية معينة. هل تتذكر مبادئ استخدام المفاتيح في المواقف العادية المذكورة سابقًا؟ إنه ليس الوضع العادي الآن. لم يتم إرجاع المفتاح الذي حصلت عليه أبدًا ، ولكن يتم إرجاعه فقط عند الخروج من كتلة الكود المتزامن.
لقد استخدمت أيضًا الرجل الذي أراد استخدام غرفتين مغلقتين على التوالي لتقديم مثال. كيف يمكنني الاستمرار في استخدام واحد آخر بعد استخدامه؟ استخدم كتل التعليمات البرمجية المتزامنة. قم أولاً بإنشاء مؤشر ترابط آخر ، وقم بعمل كتلة رمز متزامنة ، وقم بتوجيه قفل كتلة الرمز إلى مفتاح المنزل. ثم ابدأ هذا الموضوع. طالما يمكنك الحصول على مفتاح المنزل عند إدخال كتلة الرمز هذه ، يمكنك الاحتفاظ به حتى تخرج من كتلة الرمز هذه. بمعنى آخر ، يمكنك حتى اجتياز جميع الغرف المقفلة في هذه الغرفة ، أو حتى النوم (10*60*1000) ، ولا يزال هناك 1000 موضوع ينتظر هذا المفتاح عند الباب. ممتعة جدا.
سنتحدث هنا عن العلاقة بين طريقة النوم () والمفتاح. إذا اضطر مؤشر ترابط إلى النوم () بعد الحصول على المفتاح ولم يكمل المحتوى المتزامن ، فلا يزال المفتاح موجودًا. لن يتم إرجاع المفتاح حتى يتم تشغيله مرة أخرى ويكمل جميع المحتوى المتزامن. تذكر أن هذا الرجل قد سئم من العمل ، لذلك ذهب لأخذ قسطًا من الراحة ، ولم ينهي ما سيفعله. من أجل تجنب دخول الآخرين إلى الغرفة وإجراء فوضى ، عليه أن يرتدي المفتاح الوحيد على جسده حتى عندما ينام.
أخيرًا ، قد يسأل بعض الأشخاص ، لماذا تحتاج إلى مفتاح لفتح بدلاً من المفتاح والباب؟ أعتقد أن هذا أمر محض بسبب التعقيد. بالطبع ، مفتاح واحد وباب واحد أكثر أمانًا ، لكنه سيشمل العديد من المشاكل. التوليد ، التخزين ، الاستحواذ ، العودة ، إلخ. من المفاتيح. قد يزداد تعقيدها في التسلسلات الهندسية مع زيادة طريقة التزامن ، مما يؤثر بشكل خطير على الكفاءة. هذا هو أيضا مفاضلة. ما مدى غير المرغوب فيه لزيادة السلامة قليلاً ، مما يؤدي إلى انخفاض كبير في الكفاءة.
مثال بسيط على المزامنة
الفئة العامة TextTrathread {public static void main (string [] args) {txtthread tt = new txtthroad () ؛ موضوع جديد (TT) .start () ؛ موضوع جديد (TT) .start () ؛ موضوع جديد (TT) .start () ؛ موضوع جديد (TT) .start () ؛ }} class txtthread تنفذ runnable {int num = 100 ؛ string str = new string () ؛ public void run () {synchronized (str) {while (num> 0) {try {thread.sleep (1) ؛ } catch (استثناء e) {e.getMessage () ؛ } system.out.println (thread.currentThRead (). getName () + "هذا هو" + num--) ؛ }}}}في المثال أعلاه ، من أجل إنشاء اختلاف زمني ، أي فرصة لاتخاذ خطأ ، يتم استخدام thread.sleep (10).
آلية دعم Java ومزامنة التزامن من أجل multithreading شائعة جدًا. يبدو أن استخدام الكلمة الرئيسية المتزامنة يمكن أن يحل بسهولة مشكلة مزامنة البيانات المشتركة المتعددة مؤشرات الترقيم. ماذا بالضبط؟ من الضروري أيضًا أن يكون لديك فهم متعمق لدور الكلمات الرئيسية المتزامنة قبل أن تتمكن من اتخاذ استنتاج.
بشكل عام ، يمكن استخدام الكلمة الرئيسية المتزامنة كمعدل للوظيفة أو كبيان داخل الوظيفة ، وهي طريقة التزامن وكتلة عبارة المزامنة التي يتم ذكرها عادةً. إذا قمت بتصنيفها بعناية أكبر ، فيمكن أن تعمل المزامنة على متغيرات المثيل ، ومراجع الكائنات ، والوظائف الثابتة ، والحرفية الفئة (اسم الثوابت الحرفية للصف).
قبل أن نوضح أكثر ، نحتاج إلى توضيح بضع نقاط:
أ. سواء تمت إضافة الكلمة الرئيسية المتزامنة إلى طريقة أو كائن ما ، فإن القفل الذي يكتسبه هو كائن ، بدلاً من معالجة قطعة من الكود أو الوظيفة كقفل ، ومن المرجح أن تكون طريقة التزامن أكثر
وصول الكائن إلى موضوعه.
ب. لكل كائن قفل واحد فقط مرتبط به.
يتطلب تنفيذ التزامن الكثير من النفقات العامة لتكلفة النظام وقد يتسبب في حدوث طريق مسدود ، لذلك حاول تجنب التحكم في التزامن غير الضروري.
بعد ذلك ، دعنا نناقش تأثير المزامنة باستخدام أماكن مختلفة على الكود:
على افتراض أن P1 و P2 هما كائنات مختلفة من نفس الفئة ، فإن هذه الفئة تحدد كتل المزامنة أو طرق التزامن في المواقف التالية ، ويمكن أن يطلق عليها P1 و P2.
1. عند استخدام المزامنة كمعدل دالة ، يكون رمز المثال كما يلي:
methodaaaa () {// ...…}هذه هي طريقة التزامن. إذن ما هو الكائن الذي تم قفله في هذا الوقت؟ ما يقفله هو تسمية هذا كائن الطريقة المتزامنة. وهذا يعني أنه عندما ينفذ كائن P1 طريقة التزامن هذه في مؤشرات الترابط المختلفة ، سيتم تشكيل الاستبعاد المتبادل بينهما لتحقيق تأثير المزامنة. ومع ذلك ، فإن كائنًا آخر P2 الذي تم إنشاؤه بواسطة فئة ينتمي إليه هذا الكائن يمكنه استدعاء هذه الطريقة بشكل تعسفي مع إضافة الكلمة الرئيسية المتزامنة.
رمز المثال أعلاه يعادل الرمز التالي:
public void methodaaa () {synchronized (this) // (1) {// ... ..}}(1) ماذا يعني هذا في هذه النقطة؟ إنه يشير إلى الكائن الذي يطلق على هذه الطريقة ، مثل P1. يمكن ملاحظة أن طريقة التزامن هي في الأساس لتطبيق متزامن على مرجع الكائن. فقط الخيط الذي حصل على قفل كائن P1 يمكنه استدعاء طريقة مزامنة P1. بالنسبة لـ P2 ، لا علاقة لقفل P1 به. قد يتخلص البرنامج أيضًا من التحكم في آلية التزامن في هذا الموقف ، مما تسبب في ارتباك البيانات: ((
2. مزامنة الكتل ، رمز العينة كما يلي:
طريقة الفراغ العام 3 (SomeObject SO) {Synchronized (SO) {// ... ..}}في هذا الوقت ، القفل هو كائن SO. كل من يحصل على القفل يمكنه تشغيل الكود الذي يتحكم فيه. عندما يكون هناك كائن واضح كقفل ، يمكنك كتابة البرنامج مثل هذا ، ولكن عندما لا يكون هناك كائن واضح كقفل ويريد فقط أن تتم مزامنة قطعة من التعليمات البرمجية ، يمكنك إنشاء متغير مثيل خاص (يجب أن يكون كائنًا) ليكون بمثابة قفل:
class foo تنفذ Runnable {private byte [] lock = new byte [0] ؛ // مثيل خاص متغير الفراغ العام methoda () {synchronized (قفل) {// ...}} // ... ..}ملاحظة: تكون كائنات صفيف البايت ذات الطول الصفري أكثر اقتصادا من أي كائن لإنشاء رمز بايت متجمع: 3 فقط مطلوبة لإنشاء كائن بايت بطول صفر ، بينما يتطلب كائن كائن () كائن جديد () 7 مواد أوبديات.
3. استخدم الوظيفة المتزامنة إلى ثابت ، رمز المثال هو كما يلي:
class foo {public synchronized static void methodaaa () // synchronized static function {//…. } public void methodbbb () {synchronized (foo.class) // class miterتستخدم طريقة methodbbb () في الكود الفئة الحرفية كقفل. لها نفس تأثير الوظيفة الثابتة المتزامنة. القفل الذي تم الحصول عليه مميز للغاية. إنه الفئة التي ينتمي إليها الكائن الذي يتصل به هذه الطريقة حاليًا (فئة ، وليس كائنًا محددًا تم إنشاؤه بواسطة هذه الفئة).
أتذكر أنه في كتاب "Java الفعال" ، رأيت أنه باستخدام foo.class و p1.getclass () كأقفال متزامنة مختلفة ، ولا يمكن استخدام p1.getclass () لتحقيق الغرض من قفل هذه الفئة. يشير P1 إلى كائن تم إنشاؤه بواسطة فئة FOO.
يمكن استنتاج أنه إذا حددت الفئة وظيفة ثابتة متزامنة A ودالة مثيل متزامنة B ، فلن يشكل الكائن نفسه من هذه الفئة المزامنة عند الوصول إلى طريقتين A و B في مؤشرات ترابط متعددة ، لأن أقفالها مختلفة. إن قفل الطريقة A هو الكائن OBJ ، في حين أن قفل B هو الفئة التي ينتمي إليها OBJ.
الملخص كما يلي:
اكتشاف الأقفال المتزامنة الكائنات التي يمكن أن تساعدنا في تصميم برامج متعددة الخيوط أكثر أمانًا. هناك أيضًا بعض النصائح لإمكانية الوصول المتزامن إلى الموارد المشتركة أكثر أمانًا:
1. تحديد متغير المثيل الخاص بـ Private + طريقة الحصول على ، بدلاً من متغير المثيل للجمهور/المحمي. إذا تم تعريف المتغير على أنه عام ، فيمكن للكائن تجاوز التحكم في طريقة التزامن والحصول عليه مباشرة وتغييره. هذا هو أيضا واحدة من أساليب التنفيذ القياسية لجافابين.
2. إذا كان متغير المثيل هو كائن ، مثل صفيف أو قائمة ArrayList ، فإن الطريقة أعلاه لا تزال غير آمنة ، لأنه عندما يحصل كائن خارجي على كائن المثيل من خلال طريقة GET ويشير إلى كائن آخر ، فإن المتغير الخاص سيتغير ، وهو أمر غير خطير للغاية. في هذا الوقت ، تحتاج إلى إضافة متزامن إلى طريقة GET ، وإرجاع الاستنساخ () فقط من هذا الكائن الخاص ، بحيث يحصل المتصل على مرجع إلى نسخة الكائن
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.