سؤال

ماذا يمكن أن يكون فهم ما يلي؟
لقد مررت هذا انشر في SO ولكن لا يزال في حيرة من أمره لتجميعه.

كود1:

synchronized(this){ 
// some code
}

كود2:

Object lock = new Object();

synchronized(lock){
// some code
}

أي برنامج تعليمي، أو بعض الروابط لشرح متزامنة مثل ما يشرحونها للطفل؟

هل كانت مفيدة؟

المحلول

هناك شيء واحد لم يتم ذكره في الإجابات الممتازة المقدمة بالفعل وهو الفرق بين code1 وcode2.في code1، تكون المزامنة على مثيل الكائن الذي تم العثور على الكود فيه، وفي code2، تكون المزامنة على كائن قفل محدد داخل الكائن.

إذا كان هناك كتلتان متزامنتان فقط في الفئة المرفقة، فلا يوجد وظيفي الفرق بين الاثنين، ولكن النظر في هذا:

class CodeOneClass {
  ...
  synchronized(this) {   // or merely "synchronized" - it defaults to this
      first protected code block
  }
  ...
  synchronized(this) {   
      second protected code block
  }
...
}

class CodeTwoClass {
  ...
  Object lock1 = new Object();
  synchronized(lock1) {   
      first protected code block
  }
  ...
  Object lock2 = new Object();
  synchronized(lock2) {   
      second protected code block
  }
...
}

إذا حاول خيطان استخدام نفس مثيل CodeOneClass، فيمكن أن يكون أحدهما فقط موجودًا أي من كتلتي التعليمات البرمجية المحمية في نفس الوقت.

لكن مع المصطلح الثاني، لديك المرونة لتقول أنه من الآمن أن يكون أحد الخيوط في الكتلة المحمية الأولى، وأن يكون آخر في الكتلة الأخرى.لاحظ أنه إذا كانت الأقفال هي نفسها (كلاهما متزامنان على نفس كائن القفل)، فسيكون السلوك هو الأول.

هناك اختلافات أخرى.بدأ بعض الكتاب في الإشارة إلى المشكلات المتعلقة بـ متزامنة (هذا) - أود أن أشير لك إلى مشاركة أخرى هنا على SO:تجنب المزامنة (هذا) في Java؟

أوصي بشدة بقراءته والمشاركات الثلاث التي يرتبط بها.

نصائح أخرى

وأساسا هناك "قفل" المقترنة بكل كائن في جافا.

وعندما يصل موضوع دعوة إلى متزامنة (شيء)، فقد لاكتساب خصلة من شيء قبل المتابعة. إذا كنت ترغب في السماح موضوع واحد فقط في كل مرة لتعديل حالة كائن، الشيء الأكثر وضوحا هو لمزامنة على القفل لهذا الكائن. إذا سمح أساليب مختلفة ليتم استدعاؤها في موازاة ذلك، تحتاج أقفال مختلفة لذلك.

إذا الكتابة متزامنة (هذا)، أو ببساطة متزامنة، وموضوع يجب الحصول على قفل المرتبطة الكائن الحالي (وهو ما يسمى طريقة).

ملحوظة أنه منذ جافا 5.0 هناك تقدم حزمة المتزامنة المناسبة <لأ href = "http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/Lock.html" يختلط = "noreferrer نوفولو"> أقفال التي يمكن استخدامها بدلا من التزامن.

وضع الكود داخل a synchronized تعني الكتلة بشكل أساسي أنه "بمجرد بدء تشغيل هذا الرمز، لا يمكن تشغيل التعليمات البرمجية الأخرى التي تحتاج إلى استخدام هذا الكائن في نفس الوقت."

لذلك، إذا كان الموضوع رقم 2 ينفذ التعليمات البرمجية في ملفك code2 كتلة، عندما يتعلق الأمر ب synchronized(lock) يجب أن ينظر بشكل فعال في جميع سلاسل الرسائل الأخرى للتأكد من عدم قيام أي شخص آخر بتشغيل التعليمات البرمجية "المتزامنة" مع lock الكائن في الوقت الراهن.الموضوع رقم 1 قيد التشغيل بالتأكيد بعض رمز في نفس الوقت، ولكن قد يكون رمزًا غير ذي صلة تمامًا.إذا كان الأمر كذلك، فمن الآمن أن يبدأ الموضوع رقم 2 في تشغيل "some code" أشياء.

وفي الوقت نفسه، إذا وصل الموضوع رقم 1 إلى synchronized(this) block، يجب عليه أيضًا التوقف مؤقتًا ومعرفة ما إذا كانت هناك أي سلاسل رسائل أخرى تستخدم this.لو this هو نفس الكائن lock, ، لدينا مشكلة.لقد قيل لنا أن مؤشر ترابط واحد فقط يمكنه استخدام هذا الكائن (في كتلة متزامنة) في نفس الوقت.ومع ذلك فإن الموضوع رقم 2 يستخدمه بالفعل.الموضوع رقم 1 يجب الإنتظار..و انتظر...و انتظر...حتى ينتهي الموضوع رقم 2 في النهاية.ثم يمكننا المضي قدما.

والنتيجة النهائية هي أن واحد فقط synchronized يمكن تشغيل الكتلة في وقت واحد (مع كائن معين بالطبع).

لنفترض أن لديك Account كائن له طريقة:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   if (accountBalance >= debitAmount) {
      accountBalance -= debitAmount;
      beneficiary.credit(debitAmount);
   }
   else {
      throw new InsufficientFundsException();
   }
}

لنفترض الآن أن لديك حسابًا برصيد 100 يورو، وحصلت على محاولتين لخصم 70 يورو منه.إذا حدث الخصمان في نفس الوقت، فيمكنك الحصول على حالة السباق مثله:

  • الخصم الأول يتحقق من رصيد الحساب:100 >= 70، هكذا نجح
  • الخصم الثاني يتحقق من رصيد الحساب:100 >= 70، هكذا نجح
  • يتم تنفيذ الخصم الأول؛يصبح رصيد الحساب 30
  • يتم تنفيذ الخصم الثاني؛يصبح رصيد الحساب -40. لا ينبغي أن يسمح

يمكننا منع هذا الوضع المزري من خلال المزامنة على Account قفل الكائن:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   synchronized (this) {
      if (accountBalance >= debitAmount) {
         accountBalance -= debitAmount;
         beneficiary.credit(debitAmount);
      }
      else {
         throw new InsufficientFundsException();
      }
   }
}

وهذا يضمن عدم إمكانية مقاطعة اختبار رصيد الحساب والخصم عن طريق اختبار آخر على رصيد الحساب.

ال برنامج تعليمي صن جافا يعد مكانًا جيدًا للبدء للحصول على معلومات حول التزامن والتأمين.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top