لماذا تزامن الموضوع
لأنه عندما يكون لدينا عدة مؤشرات ترابط للوصول إلى متغير أو كائن في نفس الوقت ، إذا كانت هناك عمليات قراءة وكتابة على حد سواء في هذه المواضيع ، فسيؤدي ذلك إلى ارتباك في القيمة المتغيرة أو حالة الكائن ، مما يؤدي إلى استثناءات البرنامج. على سبيل المثال ، إذا تم تشغيل حساب مصرفي بواسطة موضوعين في نفس الوقت ، فإن المرء يسحب 100 يوان والآخر يحفظ 100 يوان. على افتراض أن الحساب كان في الأصل 0 يوان ، ماذا سيحدث إذا حدث مؤشر ترابط السحب وخيط حفظ في نفس الوقت؟ إذا لم ينجح سحب الأموال ، فإن رصيد الحساب هو 100. إذا كان سحب المال ناجحًا ، فإن رصيد الحساب هو 0. إذن أي واحد هو؟ من الصعب شرحها بوضوح. لذلك ، التزامن متعدد الخيوط هو حل هذه المشكلة.
1. الكود عند الخروج من المزامنة
Bank.Java Package Threadtest ؛ Out .println (System.CurrentTimeMillis ()+"Save:"+Money) ؛ ::::::::::::::::::::::::: :::::::::::::::::::::: ::::: ::: void lookmoney () {system.out. () ؛ {// todo -gate catch e.printstrace () ؛ Thread (new RunNable () {Override public void run () {// todo method method stlud ice (true) {bank.submoney (100) ؛ ") ؛ جرب {thread.sleep (1000) ؛} catch (InterruptedException e) {// todo catch catch e.printstacktrace () ؛}}}}) ؛ tsub.start () ؛ tad.start () ؛
الكود بسيط للغاية ، لن أشرح ذلك. لقد اعترضت بعضهم ، هل هو فوضوي للغاية ، ولا أستطيع أن أفهم الكتابة.
رصيد حساب الرصيد غير كاف: 0
رصيد حساب الرصيد غير كاف: 100
1441790503354 الإيداع: 100
رصيد الحساب: 100
1441790504354 الإيداع: 100
رصيد الحساب: 100
1441790504354 خذ: 100
رصيد الحساب: 100
1441790505355 الإيداع: 100
رصيد الحساب: 100
1441790505355 خذ: 100
رصيد الحساب: 100
2. استخدم الكود المتزامن
(1) طريقة التزامن:
هناك طريقة لتعديل الكلمات الرئيسية المتزامنة. نظرًا لأن كل كائن في Java يحتوي على قفل مدمج ، عند تعديل الطريقة باستخدام هذه الكلمة الرئيسية ، يحمي القفل المدمج الطريقة بأكملها. قبل استدعاء هذه الطريقة ، تحتاج إلى الحصول على قفل مدمج ، وإلا فإنه سيكون في حالة حظر.
تعديل bank.java
لنلقي نظرة على نتائج الجري:
رصيد حساب الرصيد غير كاف: 0
رصيد حساب الرصيد غير كاف: 0
1441790837380SAGED: 100
رصيد الحساب: 100
1441790838380 خذ: 100
رصيد الحساب: 0
1441790838380saved: 100
رصيد الحساب: 100
1441790839381 تمت إزالته: 100
رصيد الحساب: 0
أشعر أنه يفهم على الفور.
ملاحظة: يمكن أن تعدل الكلمة الرئيسية المتزامنة أيضًا طرقًا ثابتة.
(2) مزامنة كتل الكود
وهذا يعني أن هناك كتلة عبارة تم تعديلها بواسطة كلمة رئيسية متزامنة. سيتم إضافة كتلة العبارة المعدلة بواسطة هذه الكلمة الرئيسية تلقائيًا باستخدام قفل مدمج لتحقيق التزامن
رمز bank.java كما يلي:
حزمة المرشح System.out.println (System.CurrentTimeMillis ()+"Save:"+Money) ؛ . {system.out.println ("رصيد الحساب:"+العد) ؛
نتائج التشغيل كما يلي:
رصيد حساب الرصيد غير كاف: 0
1441791806699SAVED: 100
رصيد الحساب: 100
1441791806700 خذ: 100
رصيد الحساب: 0
1441791807699SAVED: 100
رصيد الحساب: 100
التأثير مشابه للطريقة.
ملاحظة: التزامن هو عملية عالية الرأس ، لذلك يجب تقليل المحتوى المتزامن. عادة ما لا توجد حاجة لمزامنة الطريقة بأكملها ، ما عليك سوى استخدام كتلة الكود المتزامن لمزامنة رمز المفتاح.
(3) استخدام متغيرات المجال الخاصة (متقلبة) لتحقيق مزامنة الخيط
توفر الكلمة الرئيسية المتقلبة آلية خالية من القفل للوصول إلى متغيرات المجال
ب.
ج.
لا يوفر D.Volatile أي عمليات ذرية ، ولا يمكن استخدامه لتعديل المتغيرات من النوع النهائي
رمز bank.java كما يلي:
Package ThreadteSt ؛ (System.CurrentTimeMillis () + "Save:" + Money) ؛ ؛ " + العد) ؛}}
كيف هو تأثير العملية؟
رصيد حساب الرصيد غير كاف: 0
رصيد حساب الرصيد غير كاف: 100
1441792010959SAVED: 100
رصيد الحساب: 100
1441792011960 خذ: 100
رصيد الحساب: 0
1441792011961Saved: 100
رصيد الحساب: 100
هل هذا لأنني لا أستطيع فهمه مرة أخرى وهو فوضوي مرة أخرى؟ لماذا هذا؟ ذلك لأن المتقلبة لا يمكن أن تضمن العمليات الذرية ، لذلك لا يمكن أن تحل محل المتزامنة. بالإضافة إلى ذلك ، سيقوم Folatile بتنظيم المترجم لتحسين الكود ، لذلك إذا كنت تستطيع استخدامه ، فلن يتم تطبيقه. مبدأه هو أنه في كل مرة يريد مؤشر ترابط الوصول إلى متغير تم تعديله بواسطة متقلبة ، يتم قراءته من الذاكرة ، وليس في ذاكرة التخزين المؤقت ، وبالتالي فإن القيمة المتغيرة التي يمكن الوصول إليها من قبل كل مؤشر ترابط هي نفسها. هذا يضمن التزامن.
(4) استخدم قفل إعادة الدخول لتحقيق مزامنة الخيط
تمت إضافة حزمة java.util.current جديدة إلى Javase5.0 لدعم التزامن. فئة REENTRANTLOCK عبارة عن قفل مُعتزم بشكل متبادل يطبق واجهة القفل.
الطرق الشائعة لفئة Reenreantlock هي:
reentrantlock (): إنشاء مثيل reentrantlock
قفل (): الحصول على القفل
Unlock (): REENTRANTLOCK ملاحظة: لدى REENTRANTLOCK () أيضًا مُنشئًا يمكنه إنشاء أقفال عادلة ، لكن لا ينصح باستخدامه لأنه يمكن أن يقلل بشكل كبير من كفاءة تشغيل البرنامج.
تم تعديل رمز bank.java على النحو التالي:
حزمة الخيط ؛ //تحتاج إلى إعلان قفل القفل الخاص = جديد reentrantlock () ؛ TLN (System .CurrentTimeMillis () + "Save:" + Money) ؛ IF (COUNT - Money <0) {system.out.println ( ؛
كيف هو تأثير العملية؟
رصيد حساب الرصيد غير كاف: 0
رصيد حساب الرصيد غير كاف: 0
1441792891934 الإيداع: 100
رصيد الحساب: 100
1441792892935SAVED: 100
رصيد الحساب: 200
1441792892954 خذ: 100
رصيد الحساب: 100
التأثير مشابه للطريقتين الأولين.
إذا تمكنت الكلمة الرئيسية المتزامنة من تلبية احتياجات المستخدمين ، فاستخدم المزامنة لأنه يمكن أن تبسيط الرمز. إذا كنت بحاجة إلى المزيد من الوظائف المتقدمة ، فاستخدم فئة REENTRANTLOCK.
(5) استخدم المتغيرات المحلية لتحقيق مزامنة الخيط
رمز bank.java كما يلي:
حزمة الخيط إرجاع 0 ؛ ) ؛ ()- Money) ؛ العد.
تأثير الجري:
رصيد حساب الرصيد غير كاف: 0
رصيد حساب الرصيد غير كاف: 0
1441794247939Saved: 100
رصيد الحساب: 100
توازن غير كاف
1441794248940save: 100
رصيد الحساب: 0
رصيد الحساب: 200
رصيد حساب الرصيد غير كاف: 0
1441794249941Saved: 100
رصيد الحساب: 300
بعد رؤية تأثير العملية ، كنت مرتبكًا في البداية. ألق نظرة على مبدأ Threadlocal:
إذا كنت تستخدم ThreadLocal لإدارة المتغيرات ، فسيحصل كل مؤشر ترابط باستخدام المتغير على نسخة من المتغير ، والنسخ مستقلة عن بعضها البعض ، بحيث يمكن لكل مؤشر ترابط تعديل نسخته الخاصة من المتغير عند الإرادة دون التأثير على مؤشرات الترابط الأخرى. الآن أفهم. لذلك سيحدث التأثير أعلاه.
آلية Threadlocal و Mychronization
أ.
ب.
الآن أفهم. لكل منها مزاياها وعيوبها ولها سيناريوهات قابلة للتطبيق.