في البرمجة متعددة الخيوط ، يجب أن تكون القضية الأكثر أهمية والأكثر اهتمامًا هي قضية التزامن ، وهي نقطة صعبة ونواة.
من النسخة المبكرة من JDK المتزامنة والمتقلب ، إلى واجهة القفل في java.util.concurrent.locks المقدمة في JDK 1.5 (تشمل التطبيقات readlock و writelock و reentrantlock) ، وتنفيذ multi-throading أيضًا بشكل تدريجي.
ما هي الآلية المستخدمة للتحكم في التزامن؟ رد الفعل الأول هو القفل ، والذي كان ينبغي أن يتعرض له عند تعلم نظام التشغيل وقاعدة البيانات. في برامج Java متعددة الخيوط ، عندما تتنافس برامج متعددة على نفس المورد ، من أجل منع تآكل الموارد ، يتم تعيين مؤشر الترابط الأول للوصول إلى المورد قفل كائن ، ويجب أن تنتظر الأجيال اللاحقة إصدار قفل الكائن هذا.
نعم ، الشيء الأكثر اهتمامًا بشأن مزامنة خيوط Java هو استخدام الموارد المشتركة.
دعونا أولاً نفهم بعض الموارد المشتركة التي تتوفر خيوطها.
من JVM ، نحتاج إلى تنسيق البيانات المشتركة بواسطة مؤشرات الترابط:
1. متغير مثيل يتم حفظه في الكومة ؛ 2. متغير الفصل المحفوظ في منطقة الطريقة.
عندما يقوم جهاز Java Virtual بتحميل فئة ، فسيتم ربط كل كائن أو فئة بشاشة لحماية متغير مثيل الكائن أو متغير الفئة ؛ بالطبع ، إذا لم يكن للكائن أي متغيرات مثيل ، أو لا يوجد لدى الفئة متغيرات ، فلن تراقب الشاشة شيئًا.
من أجل تحقيق Mutex للشاشات المذكورة أعلاه ، يربط الجهاز الظاهري قفلًا (يُطلق عليه أيضًا قفل غير مرئي) لكل كائن أو فئة. اسمحوا لي أن أشرح هنا أن أقفال الفئة يتم تنفيذها أيضًا من خلال أقفال الكائنات ، لأنه عندما يتم تحميل الفصل ، سيقوم JVM بإنشاء مثيل من java.lang.class لكل فئة ؛ لذلك عندما يكون القفل ضد كائن ، يتم قفل كائن الفئة من هذه الفئة.
بالإضافة إلى ذلك ، يمكن لخيط قفل كائن عدة مرات ، وهو ما يتوافق مع إصدارات متعددة ؛ إنها آلة حاسبة قفل توفرها JVM لكل قفل كائن. تتم إضافة القفل الأخير 1 ، والنقص المقابل 1 ، وعندما تكون قيمة الآلة الحاسبة 0 ، يتم إصداره. يتم استخدام قفل الكائن هذا بواسطة الشاشة داخل JVM ويتم إنشاءه تلقائيًا بواسطة JVM. لا يحتاج جميع المبرمجين إلى إضافته بمفردهم.
بعد تقديم مبدأ التزامن في Java ، سنصل إلى الموضوع ونتحدث أولاً عن استخدام المزامنة. سيتم تقديم التزامنات الأخرى في الفصول التالية.
لنحاول تشغيل مثال أولاً.
package thread_test ؛ / *** اختبار البرامج المتعددة المؤشرات الموسيقية التي تمدد تنفيذ فئة مؤشرات الترابط**/ اختبار الفئة العامة يمتد Thread {private int threadnum ؛ testTresThread (int threadnum) {this.threadnum = threadnum ؛ } Override public synchronized void run () {for (int i = 0 ؛ i <1000 ؛ i ++) {system.out.println ("no." + threadnum + ":" + i) ؛ }} public static void main (string [] args) يرمي الاستثناء {for (int i = 0 ؛ i <10 ؛ i ++) {new testthread (i) .start () ؛ thread.sleep (1) ؛ }}}
نتائج التشغيل:
No.0: 887 No.0: 888 No.0: 889 No.0: 890 No.0: 891 No.0: 892 No.0: 893 No.0: 894 No.7: 122 No.7: 123 No.7: 124
ما سبق هو مجرد مقطع ، يشرح مشكلة.
إذا كنت حريصًا ، فستجد أن رقم 0: 894 يتبعه رقم 7: 122 ، مما يعني أنه لا يبدأ من 0 إلى 999.
يقال أن المزامنة يمكن أن تنفذ طرق المزامنة أو كتل المزامنة ، لماذا لا يمكن أن تعمل هنا؟
دعنا أولاً نحلل آلية التزامن. يتم تحقيق التزامن من خلال القفل. إذن في المثال أعلاه ، ما هو الكائن المقفل أو ما هو الفئة المقفلة؟ هناك متغيران في الداخل ، أحدهما هو والآخر هو threadnum ؛ أنا داخلي للطريقة ، و threadnum خاص.
دعونا نتعرف على آلية الجري المتماسكة:
في برنامج Java ، عند استخدام كتلة أو طريقة متزامنة ، يتم تمييز هذه المنطقة للمراقبة ؛ بينما عندما يقوم JVM بمعالجة البرنامج ، عندما يدخل البرنامج إلى منطقة المراقبة ، فإنه سيغلق الكائن أو الفئة تلقائيًا.
إذن في المثال أعلاه ، ما الذي يتم قفله بعد استخدام الكلمة الرئيسية المتزامنة؟
عند تزامن الأسلوب ، قفل كائن المثيل الذي يطلق على الطريقة نفسها كقفل الكائن. في هذا المثال ، تحتوي مؤشرات الترابط العشرة على كائنات فئة TestThread الخاصة بها ، وبالتالي فإن قفل الكائن الذي تم الحصول عليه هو أيضًا قفل الكائن الخاص به وليس له أي علاقة مع مؤشرات الترابط الأخرى.
لتنفيذ قفل الطريقة ، يجب قفل الكائنات المشتركة.
قم بتغيير المثال أعلاه ثم ألقِ نظرة:
package thread_test ؛ / *** اختبار البرامج المتعددة المؤشرات الموسيقية التي تمدد تنفيذ فئة مؤشرات الترابط**/ اختبار الفئة العامة يمتد Thread {private int threadnum ؛ علم السلسلة الخاص // Mark Public TestTreThread (int threadnum ، علامة سلسلة) {this.threadnum = threadnum ؛ this.flag = flag ؛ } Override public void run () {synchronized (flag) {for (int i = 0 ؛ i <1000 ؛ i ++) {system.out.println ("no." + threadnum + ":" + i) ؛ }}} public static void main (string [] args) يلقي استثناء {string flag = new string ("flag") ؛ لـ (int i = 0 ؛ i <10 ؛ i ++) {new TestTread (i ، flag) .start () ؛ thread.sleep (1) ؛ }}}
هذا يضيف أيضا علامة مشتركة. ثم ، تتم مزامنة علامة العلم من خلال الكتلة المتزامنة ؛ هذا يلبي شروط قفل الكائن المشترك.
نعم ، لقد جاءت نتائج التشغيل بالترتيب.
من خلال الكتلة المتزامنة ، حدد اكتساب أقفال الكائن لتحقيق التزامن. هل هناك أي طرق أخرى يمكن تنفيذها من خلال الطريقة المتزامنة؟
وفقًا لمبدأ التزامن: إذا كان يمكن الحصول على قفل كائن مشترك أو قفل فئة ، فيمكن تحقيق التزامن. هل يمكننا تحقيق ذلك من خلال مشاركة قفل الفصل؟
نعم ، يمكننا استخدام طرق التزامن الثابت. وفقًا لخصائص الأساليب الثابتة ، فإنه يسمح فقط بإجراء كائن الفصل نفسه ، ولا يمكن استدعاؤه من خلال إنشاء كائن فئة. ثم إذا حصلت على قفل هذه الطريقة الثابتة ، فستحصل على قفل الفئة ، وسيكون قفل الفئة هذا كل أقفال فئة TestThread ، ويتم تحقيق الغرض من الحصول على أقفال الفئة المشتركة.
رمز التنفيذ كما يلي:
package thread_test ؛ / ** * اختبار البرامج متعددة الخيوط التي تمد تنفيذ فئة مؤشرات الترابط * * Author ciding * createTime 7 ديسمبر ، 2011 9:37:25 AM * */ TestTrase Public Class يمتد Thread {private int threadnum ؛ testTresThread (int threadnum) {this.threadnum = threadnum ؛ } staticest void staticest (int threadnum) {int (int i = 0 ؛ i <1000 ؛ i ++) {system.out.println ("no." + threadnum + ":" + i) ؛ }} public static void main (string [] args) يرمي الاستثناء {for (int i = 0 ؛ i <10 ؛ i ++) {new testthread (i) .start () ؛ thread.sleep (1) ؛ }} Override public void run () {Statictest (threadnum) ؛ }} تم حذف نتيجة التشغيل ، كما في المثال الثاني.
يشرح المحتوى أعلاه بشكل أساسي مشكلتين: كتل المزامنة وطرق التزامن.
1. كتلة متزامنة: قفل الكائن المكتسب هو قفل كائن العلم في المزامنة (العلم).
2. طريقة التزامن: كائن الفئة الذي ينتمي إليه الطريقة ، وقفل كائن الفئة.
سيتم مزامنة طريقة المزامنة الثابتة بالتأكيد حيث سيتم مشاركة مؤشرات ترابط متعددة.
بدلاً من طرق المزامنة الثابتة ، سيتم مزامنتها فقط في وضع Singleton.