انسخ رمز الكود كما يلي:
تشغيل الفراغ المتزامن العام ()
{
}
كما يتبين من الكود أعلاه، طالما تمت إضافة الكلمة الأساسية المتزامنة بين void و public، فيمكن مزامنة طريقة التشغيل، وهذا يعني أنه بالنسبة لمثيل الكائن من نفس فئة Java، يمكن مزامنة طريقة التشغيل فقط يتم استدعاؤها بواسطة مؤشر ترابط واحد في نفس الوقت، ولا يمكن استدعاؤها بواسطة سلاسل رسائل أخرى إلا بعد تنفيذ التشغيل الحالي. حتى إذا كان الخيط الحالي ينفذ طريقة العائد في طريقة التشغيل، فإنه يتوقف مؤقتًا فقط لفترة من الوقت. نظرًا لأن الخيوط الأخرى لا يمكنها تنفيذ طريقة التشغيل، فسيستمر الخيط الحالي في التنفيذ في النهاية. ألق نظرة على الكود التالي أولاً:
ترتبط الكلمة الأساسية المتزامنة بمثيل كائن واحد فقط
انسخ رمز الكود كما يلي:
اختبار الطبقة
{
طريقة الفراغ المتزامنة العامة ()
{
}
}
تقوم الطبقة العامة Sync بتنفيذ Runnable
{
اختبار اختبار خاص؛
تشغيل الفراغ العام ()
{
test.method();
}
المزامنة العامة (اختبار اختبار)
{
this.test = test;
}
يلقي الفراغ الرئيسي العام (String[] args) استثناءً
{
اختبار test1 = اختبار جديد ()؛
اختبار test2 = اختبار جديد ()؛
Sync sync1 = new Sync(test1);
Sync sync2 = new Sync(test2);
موضوع جديد(sync1).start();
موضوع جديد(sync2).start();
}
}
طرق الطريقة في فئة الاختبار متزامنة. لكن الكود أعلاه ينشئ مثيلين لفئة الاختبار، لذلك يتم تنفيذ أساليب الاختبار 1 والاختبار 2 بشكل منفصل. لمزامنة الطرق، يجب عليك تمرير مثيل من نفس فئة الاختبار إلى مُنشئها عند إنشاء مثيل لفئة Sync، كما هو موضح في الكود التالي:
Sync sync1 = new Sync(test1);
لا يمكنك استخدام المزامنة لمزامنة الطرق غير الثابتة فحسب، بل يمكنك أيضًا استخدام المزامنة لمزامنة الطرق الثابتة. على سبيل المثال، يمكن تعريف طريقة الطريقة على النحو التالي:
انسخ رمز الكود كما يلي:
اختبار الطبقة
{
طريقة الفراغ المتزامنة العامة الثابتة () { }
}
قم بإنشاء مثيل كائن لفئة الاختبار كما يلي:
اختبار الاختبار = اختبار جديد ()؛
بالنسبة للطرق الثابتة، طالما تمت إضافة الكلمة الأساسية المتزامنة، فستتم مزامنة الطريقة. سواء كنت تستخدم test.method() أو Test.method() لاستدعاء طريقة الطريقة، فستتم مزامنة الطريقة ولا توجد مشكلة في التعدد أمثلة على الأساليب غير الثابتة
من بين أنماط التصميم الـ 23، يعد وضع Singleton أيضًا غير آمن للخيط إذا تم تصميمه وفقًا للطرق التقليدية. التعليمة البرمجية التالية هي وضع Singleton غير آمن للخيط.
انسخ رمز الكود كما يلي:
اختبار الحزمة
// الوضع الفردي الآمن للخيط
فئة سينجلتون
{
عينة مفردة ثابتة خاصة؛
سينجلتون خاص ()
{
}
getInstance المفرد الثابت العام ()
{
إذا (عينة == فارغة)
{
Thread.yield(); // من أجل تضخيم انعدام أمان الخيط في وضع Singleton
عينة = مفردة جديدة () ؛
}
عينة العودة
}
}
الطبقة العامة MyThread تمتد الموضوع
{
تشغيل الفراغ العام ()
{
Singleton Singleton = Singleton.getInstance();
System.out.println(singleton.hashCode());
}
الفراغ العام الثابت الرئيسي (String[] args)
{
Thread threads[] = new Thread[5];
لـ (int i = 0; i < Threads.length; i++)
Threads[i] = new MyThread();
لـ (int i = 0; i < Threads.length; i++)
المواضيع[i].start();
}
}
يتم استدعاء طريقة العائد في الكود أعلاه لإظهار عدم أمان الخيط في الوضع المفرد. إذا تمت إزالة هذا السطر، فإن التنفيذ أعلاه لا يزال غير آمن، ولكن احتمال حدوثه أقل بكثير.
نتائج تشغيل البرنامج هي كما يلي:
انسخ رمز الكود كما يلي:
25358555
26399554
7051261
29855319
5383406
قد تختلف نتائج التشغيل المذكورة أعلاه باختلاف بيئات التشغيل، ولكن عمومًا لن تكون خطوط الإخراج الخمسة متماثلة تمامًا. كما يتبين من هذا الناتج، هناك خمس كائنات تم الحصول عليها من خلال طريقة getInstance، وليست واحدة كما توقعنا. وذلك لأنه عندما ينفذ مؤشر ترابط Thread.yield()، فإنه يقوم بتسليم موارد وحدة المعالجة المركزية إلى مؤشر ترابط آخر. نظرًا لعدم تنفيذ عبارة إنشاء مثيل كائن Singleton عند التبديل بين سلاسل الرسائل، فإن جميع سلاسل الرسائل هذه تمر بحكم if، لذلك سيتم إنشاء خمس مثيلات للكائن (يمكن إنشاء أربعة مثيلات للكائن، اعتمادًا على عدد سلاسل الرسائل التي تم تمريرها). حكم if قبل إنشاء كائن Singleton، فقد تكون النتيجة مختلفة في كل مرة يتم تشغيله).
لجعل الوضع المفرد أعلاه آمنًا، ما عليك سوى إضافة الكلمة الأساسية المتزامنة إلى getInstance. الرمز هو كما يلي:
getInstance() المفردة الثابتة العامة المتزامنة { }
بالطبع هناك طريقة أبسط، وهي إنشاء كائن Singleton عند تعريف المتغير Singleton، ويكون الكود كما يلي:
عينة مفردة نهائية ثابتة خاصة = مفردة جديدة () ؛
ثم قم فقط بإرجاع العينة مباشرة في طريقة getInstance. على الرغم من أن هذه الطريقة بسيطة، إلا أنها ليست مرنة في إنشاء كائن Singleton في طريقة getInstance. يمكن للقراء اختيار استخدام طرق مختلفة لتنفيذ النمط المفرد وفقًا للاحتياجات المحددة.
هناك أربع نقاط يجب ملاحظتها عند استخدام الكلمة الأساسية المتزامنة:
1. لا يمكن وراثة الكلمة الأساسية المتزامنة.
على الرغم من أنه يمكنك استخدام المزامنة لتحديد الأساليب، إلا أن المزامنة ليست جزءًا من تعريف الطريقة، لذلك لا يمكن وراثة الكلمة الأساسية المتزامنة. إذا كانت إحدى الطرق في الفئة الأصلية تستخدم الكلمة الأساسية المتزامنة وتتجاوز هذه الطريقة في الفئة الفرعية، فلن تتم مزامنة الطريقة الموجودة في الفئة الفرعية بشكل افتراضي ويجب تحديدها بشكل صريح في الفئة الفرعية، فما عليك سوى إضافة الكلمة الأساسية المتزامنة إلى الطريقة. بالطبع، يمكنك أيضًا استدعاء الطريقة المقابلة في الفئة الأصلية في طريقة الفئة الفرعية. بهذه الطريقة، على الرغم من أن الطريقة في الفئة الفرعية ليست متزامنة، فإن الفئة الفرعية تستدعي طريقة المزامنة للفئة الأصلية فئة فرعية تعادل التزامن. رموز الأمثلة لهاتين الطريقتين هي كما يلي:
أضف الكلمة الأساسية المتزامنة إلى طريقة الفئة الفرعية
انسخ رمز الكود كما يلي:
الوالدين الصف
{
طريقة الفراغ العامة المتزامنة () { }
}
فئة الطفل يمتد الوالد
{
طريقة الفراغ العامة المتزامنة () { }
}
استدعاء الطريقة المتزامنة للفئة الأصلية في طريقة الفئة الفرعية
انسخ رمز الكود كما يلي:
الوالدين الصف
{
طريقة الفراغ العامة المتزامنة () { }
}
فئة الطفل يمتد الوالد
{
طريقة الفراغ العامة () {super.method ())؛
}
2. لا يمكن استخدام الكلمة الأساسية المتزامنة عند تحديد طرق الواجهة.
3. لا يمكن للمنشئ استخدام الكلمة الأساسية المتزامنة، ولكن يمكنه استخدام الكتلة المتزامنة التي سيتم مناقشتها في القسم التالي للمزامنة.
4. يمكن وضعها بحرية متزامنة.
في الأمثلة السابقة، يتم وضع الكلمة الأساسية المتزامنة أمام نوع الإرجاع الخاص بالأسلوب. ولكن هذا ليس المكان الوحيد الذي يمكن وضع المزامنة فيه. في الطرق غير الثابتة، يمكن أيضًا وضع المزامنة في مقدمة تعريف الطريقة. في الطرق الثابتة، يمكن وضع الكود المتزامن أمام الثابت كما يلي:
انسخ رمز الكود كما يلي:
طريقة الفراغ العامة المتزامنة () ؛
طريقة الفراغ العام المتزامنة () ؛
طريقة الفراغ المتزامنة العامة الثابتة () ؛
طريقة الفراغ الثابت المتزامنة العامة () ؛
طريقة الفراغ الثابتة العامة المتزامنة () ؛
ولكن يرجى ملاحظة أنه لا يمكن وضع المزامنة بعد نوع إرجاع الطريقة، على سبيل المثال، الكود التالي خاطئ:
انسخ رمز الكود كما يلي:
طريقة مزامنة الفراغ العام () ؛
طريقة مزامنة الفراغ الثابت العام () ؛
لا يمكن استخدام الكلمة الأساسية المتزامنة إلا لمزامنة الأساليب، وليس لمتغيرات الفئة. الكود التالي خاطئ أيضًا.
انسخ رمز الكود كما يلي:
int المتزامن العام n = 0;
ثابت عام متزامن int n = 0;
على الرغم من أن استخدام طريقة مزامنة الكلمات الرئيسية المتزامنة هو أسلوب المزامنة الأكثر أمانًا، إلا أن الاستخدام المكثف للكلمات الأساسية المتزامنة سيؤدي إلى استهلاك غير ضروري للموارد وفقدان الأداء. على الرغم من أنه يبدو ظاهريًا أن الأقفال المتزامنة هي طريقة ما، إلا أنها في الواقع تقفل فئة متزامنة. بمعنى آخر، إذا تم استخدام المزامنة عند تحديد كلتا الطريقتين غير الثابتتين، الطريقة 1 والطريقة 2، فلا يمكن تنفيذ الطريقة 2 قبل تنفيذ الطريقة 1. الوضع مشابه للطرق الثابتة وغير الثابتة. لكن الأساليب الثابتة وغير الثابتة لا تؤثر على بعضها البعض. ألق نظرة على الكود التالي:
انسخ رمز الكود كما يلي:
اختبار الحزمة
الطبقة العامة MyThread1 تمتد الموضوع
{
اسم طريقة السلسلة العامة؛
طريقة الفراغ الثابت العامة (سلسلة)
{
System.out.println(s);
بينما (صحيح)
}
طريقة الفراغ المتزامنة العامة 1 ()
{
الطريقة ("طريقة الطريقة 1 غير الثابتة")؛
}
طريقة الفراغ المتزامنة العامة 2 ()
{
الطريقة ("طريقة الطريقة 2 غير الثابتة")؛
}
طريقة الفراغ المتزامنة العامة الثابتة 3 ()
{
الطريقة ("طريقة الطريقة الثابتة 3")؛
}
طريقة الفراغ المتزامنة العامة الثابتة 4 ()
{
الطريقة("طريقة الطريقة الثابتة 4");
}
تشغيل الفراغ العام ()
{
يحاول
{
getClass().getMethod(methodName).invoc(this);
}
قبض (الاستثناء ه)
{
}
}
يلقي الفراغ الرئيسي العام (String[] args) استثناءً
{
MyThread1 myThread1 = new MyThread1();
لـ (int i = 1; i <= 4; i++)
{
myThread1.methodName = "method" + String.valueOf(i);
موضوع جديد(myThread1).start();
نوم(100);
}
}
}
نتائج التشغيل هي كما يلي:
انسخ رمز الكود كما يلي:
طريقة غير ثابتة 1
طريقة ثابتة 3
كما يتبين من نتائج التشغيل المذكورة أعلاه، لا يمكن تشغيل الطريقة 2 والطريقة 4 قبل اكتمال الطريقة 1 والطريقة 3. لذلك، يمكننا أن نستنتج أنه إذا استخدمت الكلمة الأساسية المتزامنة لتحديد طريقة غير ثابتة في الفصل الدراسي، فستؤثر على جميع الطرق غير الثابتة المحددة باستخدام الكلمة الأساسية المتزامنة في هذا الفصل. إذا تم تعريف طريقة ثابتة، فسوف تؤثر على جميع الطرق الثابتة المحددة باستخدام الكلمة الأساسية المتزامنة في الفصل. هذا يشبه إلى حد ما قفل الجدول في جدول البيانات، فعندما يتم تعديل السجل، يقوم النظام بقفل الجدول بأكمله، لذلك فإن الاستخدام المكثف لطريقة المزامنة هذه سيؤدي إلى تقليل أداء البرنامج بشكل كبير.