في Java ، يمكن استخدام الكلمة الرئيسية المزامنة للتحكم في مزامنة مؤشر الترابط لتحقيق الوصول المتسلسل إلى الموارد الرئيسية ، وتجنب عدم تناسق البيانات الناجم عن التنفيذ المتزامن متعدد الخيوط. مبدأ المزامنة هو شاشة كائن (قفل). يمكن للموضوع الذي يحصل على الشاشة فقط الاستمرار في التنفيذ ، وإلا فإن الخيط سينتظر للحصول على الشاشة. كل كائن أو فئة في Java لديه قفل مرتبط به. بالنسبة لكائن ، يراقب متغير المثيل لهذا الكائن. بالنسبة لفئة ما ، فإنه يراقب متغير الفئة (فئة نفسها هي كائن من فئة الفئة ، وبالتالي فإن القفل المرتبط بالفئة هو أيضًا قفل كائن). هناك طريقتان لاستخدام الكلمات الرئيسية المتزامنة: طريقة متزامنة وكتلة متزامنة. ترتبط كلا مناطق المراقبة بكائن مقدمة. عندما تصل إلى منطقة المراقبة هذه ، ستقوم JVM بإغلاق الكائن المرجعي ، وعندما يغادر ، سيتم إصدار القفل على الكائن المرجعي (سيقوم JVM بإصدار القفل عندما يكون هناك مخرج استثناء). أقفال الكائن هي آليات داخلية لـ JVM. تحتاج فقط إلى كتابة طرق التزامن أو كتل المزامنة. عند تشغيل مناطق المراقبة ، ستحصل JVM تلقائيًا على القفل أو إطلاقه.
مثال 1
دعونا نلقي نظرة أولاً على المثال الأول. في Java ، لا يوجد سوى منطقة حاسمة واحدة من نفس الكائن المسموح بالوصول إليها في نفس الوقت (جميع الطرق المتزامنة غير المنتظمة):
حزمة التزامن ؛ الفئة العامة Main8 {public static void main (string [] args) {account account = new account () ؛ حساب. الشركة = شركة جديدة (حساب) ؛ Thread CompanyThRead = Thread (Company) ؛ بنك البنك = بنك جديد (حساب) ؛ Thread BankThread = موضوع جديد (بنك) ؛ system.out.printf ("الحساب: الرصيد الأولي: ٪ f/n" ، حساب. getBalance ()) ؛ CompanyThread.start () ؛ bankthread.start () ؛ Try {// join () Method تنتظر هذين الموضوعين لإكمال CompanyThread.join () ؛ bankthread.join () ؛ system.out.printf ("الحساب: الرصيد النهائي: ٪ f/n" ، حساب. getBalance ()) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}} /*حساب*/حساب الفئة {رصيد مزدوج خاص ؛ /*إضافة بيانات واردة لتحقيق التوازن*/ public synchronized void addamount (double come) {double tmp = balance ؛ حاول {thread.sleep (10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } tmp += المبلغ ؛ التوازن = TMP ؛ } /*خصم البيانات الواردة من الرصيد الرصيد* / الفراغ العام المتزامن العام (كمية مزدوجة) {double tmp = balance ؛ حاول {thread.sleep (10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } tmp -= المبلغ ؛ التوازن = TMP ؛ } public double getBalance () {return Balance ؛ } public void setbalance (رصيد مزدوج) {this.balance = التوازن ؛ }} /*Bank*/Class Bank يطرف Runnable {حساب خاص ؛ البنك العام (حساب الحساب) {this.account = account ؛ } Override public void run () {for (int i = 0 ؛ i <100 ؛ i ++) {account.subtractamount (1000) ؛ }}} /*Company*/Class Company تنفذ Runnable {حساب خاص ؛ الشركة العامة (حساب الحساب) {this.account = account ؛ } Override public void run () {for (int i = 0 ؛ i <100 ؛ i ++) {account.addamount (1000) ؛ }}}لقد قمت بتطوير طلب محاكاة للحسابات المصرفية التي يمكن أن تتصاعد وخصم الأرصدة. يعيد هذا البرنامج شحن الحساب عن طريق استدعاء طريقة addamount () 100 مرة ، ويدعو 1000 في كل مرة ؛ ثم يقوم بخصم رصيد الحساب عن طريق استدعاء طريقة Orvictamount () 100 مرة ، وخصم 1000 في كل مرة ؛ نتوقع أن يكون الرصيد النهائي للحساب مساوياً للرصيد الأولي ، ونطبقه من خلال الكلمة الرئيسية المتزامنة.
إذا كنت ترغب في عرض مشكلة الوصول المتزامنة للبيانات المشتركة ، فأنت بحاجة فقط إلى حذف الكلمات الرئيسية المتزامنة في إعلانات طريقة Addamount () وطرحها (). بدون الكلمة الرئيسية المتزامنة ، فإن قيمة الرصيد المطبوعة غير متسقة. إذا قمت بتشغيل هذا البرنامج عدة مرات ، فستحصل على نتائج مختلفة. نظرًا لأن JVM لا يضمن ترتيب تنفيذ مؤشرات الترابط ، في كل مرة يتم تشغيلها ، ستقرأ مؤشرات الترابط وتعديل رصيد الحساب في أوامر مختلفة ، مما يؤدي إلى نتائج نهائية مختلفة.
يتم الإعلان عن طريقة الكائن باستخدام الكلمة الرئيسية المتزامنة ويمكن الوصول إليها فقط بواسطة مؤشر ترابط واحد. إذا كان مؤشر الترابط A ينفذ طريقة المزامنة SyncMethoda () ، يريد مؤشر الترابط B تنفيذ طرق التزامن الأخرى SyncMethodB () من هذا الكائن ، سيتم حظر مؤشر الترابط B حتى يكمل مؤشر الترابط A الوصول. ولكن إذا وصل الموضوع B إلى كائنات مختلفة من نفس الفئة ، فلن يتم حظر الخيط.
مثال 2
إظهار المشكلة التي يمكن الوصول إلى الأساليب المتزامنة الثابتة والطرق المتزامنة غير المنتظمة على نفس الكائن بواسطة مؤشرات ترابط متعددة في نفس الوقت. تحقق من ذلك.
حزمة التزامن ؛ الفئة العامة Main8 {public static void main (string [] args) {account account = new account () ؛ حساب. الشركة = شركة جديدة (حساب) ؛ Thread CompanyThRead = Thread (Company) ؛ بنك البنك = بنك جديد (حساب) ؛ Thread BankThread = موضوع جديد (بنك) ؛ system.out.printf ("الحساب: الرصيد الأولي: ٪ f/n" ، حساب. getBalance ()) ؛ CompanyThread.start () ؛ bankthread.start () ؛ Try {// join () Method تنتظر هذين الموضوعين لإكمال CompanyThread.join () ؛ bankthread.join () ؛ system.out.printf ("الحساب: الرصيد النهائي: ٪ f/n" ، حساب. getBalance ()) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}} /*حساب*/حساب الفئة {/*قم بتغييره إلى متغير ثابت هنا*/توازن مزدوج ثابت ثابت = 0 ؛ /*إضافة بيانات واردة إلى توازن التوازن ، لاحظ أنه يتم تعديله باستخدام addamount المتزامن الثابت الثابت*/ الثابتة العامة (Double TMP = التوازن ؛ حاول {thread.sleep (10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } tmp += المبلغ ؛ التوازن = TMP ؛ } /*قم بخصم البيانات الواردة من رصيد الرصيد* / الفراغ المزامن العام المتماسك (المبلغ المزدوج) {double tmp = balance ؛ حاول {thread.sleep (10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } tmp -= المبلغ ؛ التوازن = TMP ؛ } public double getBalance () {return Balance ؛ } public void setbalance (رصيد مزدوج) {this.balance = التوازن ؛ }} /*Bank*/Class Bank يطرف Runnable {حساب خاص ؛ البنك العام (حساب الحساب) {this.account = account ؛ } Override public void run () {for (int i = 0 ؛ i <100 ؛ i ++) {account.subtractamount (1000) ؛ }}} /*Company*/Class Company تنفذ Runnable {حساب خاص ؛ الشركة العامة (حساب الحساب) {this.account = account ؛ } Override public void run () {for (int i = 0 ؛ i <100 ؛ i ++) {account.addamount (1000) ؛ }}}لقد أضفت للتو الكلمة الرئيسية الثابتة لتعديل الرصيد في المثال السابق ، ويمكن لطريقة Addamount () أيضًا تعديل الكلمة الرئيسية الثابتة. يمكنك اختبار نتائج التنفيذ بنفسك ، وسيكون لكل تنفيذ نتيجة مختلفة!
بعض الملخص: