هل يستطيع أحد أن يفسر المراقبون موضوع والانتظار؟

StackOverflow https://stackoverflow.com/questions/226455

  •  03-07-2019
  •  | 
  •  

سؤال

وشخص في العمل طلب لمجرد الأسباب الكامنة وراء الحاجة إلى التفاف الانتظار داخل متزامنة.

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

وأنا أبحث عن وإلى حد ما في عمق لماذا أو ربما إشارة إلى مقال. لم أتمكن من العثور على واحد في جوجل سريعة.

وأوه، أيضا، كيف thread.sleep مقارنة؟

وتحرير: مجموعة كبيرة من إجابات - أنا حقا أتمنى أن اختيار أكثر من واحد لأنهم جميعا ساعدتني على فهم ما يجري

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

المحلول

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

وأو بعبارة أخرى، ليس هناك فرق بين:

public void doStuffOnThisObject()

والطريقة التالية:

public void wait()

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

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

لالإجابة على سؤالك في Thread.sleep ()، Thread.sleep () لا يضمن أن كل ما كنت حالة انتظار تم الوفاء بها. باستخدام Object.wait () وObject.notify () يسمح مبرمج لتنفيذ يدويا الحجب. فإن المواضيع افراج مرة واحدة يتم إرسالها إلى أن حالة قوبل إعلام. مثلا انتهت والقراءة من القرص ويمكن معالجته البيانات بواسطة الخيط. سوف Thread.sleep () تتطلب مبرمج لاستطلاع إذا تم استيفاء الشرط، ثم تعود مرة أخرى إلى النوم إذا كان لديه لا.

نصائح أخرى

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

لالانتظار لبعض الصفحات الأخرى لتغيير حالة إلى true وإخطار:

synchronized(o) {
  while(! checkCondition()) {
    o.wait();
  }
}

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

 Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 lock.lock();
 try {
   while (! checkCondition()) {
     condition.await();
   }
 } finally {
   lock.unlock();
 }

و}

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

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

وانتظر يتخلى عن الشاشة، لذلك يجب أن يكون ذلك في التخلي عنه. إعلام يجب أن يكون جهاز العرض أيضا.

والسبب الرئيسي لماذا تريد أن تفعل هذا هو التأكد من أن لديك الشاشة عندما كنت أعود من الانتظار () - عادة، كنت تستخدم الانتظار / إعلام بروتوكول لحماية بعض الموارد المشتركة وتريد أن تكون آمنة لمسها عند الانتظار العوائد. الشيء نفسه مع إعلام - وعادة ما يتم تغيير شيء ثم استدعاء إعلام () -. كنت تريد أن يكون جهاز العرض، وإجراء تغييرات، وندعو إعلام ()

إذا قمت بعمل وظيفة من هذا القبيل:

public void synchWait() {
   syncronized { wait(); }
}

وسوف لا يكون لديك جهاز العرض عندما عاد الانتظار - هل يمكن أن تحصل عليه، ولكن قد لا تحصل عليه المقبل

.

وهنا أفهم لماذا التقييد هو في الواقع شرط. أنا مستندة بذلك على C ++ رصد التنفيذ الذي أدليت به في حين يعود من خلال الجمع بين مزامنة ومتغير الحالة.

في ل<م> مزامنة + condition_variable = مراقبة النظام، في انتظر دعوة يحدد متغير حالة إلى حالة انتظار وتطلق مزامنة. ويشارك في متغير حالة الدولة، لذلك يجب أن يكون مؤمنا لتجنب حالات السباق بين المواضيع التي ترغب في الانتظار والمواضيع التي ترغب في إعلام. بدلا من إدخال بعد مزامنة آخر لقفل حالته، يتم استخدام مزامنة القائمة. في جاوة، يتم تأمين مزامنة بشكل صحيح عندما يملك الخيط حول إلى الانتظار الشاشة.

ومعظمهم من الانتظار ويتم إذا كان هناك شرط وتقول طابور فارغ.

If(queue is empty)
     queue.wait();

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

Synchornized(queue)
{
   if(queue is empty)
          queue.wait();
}

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

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