لماذا جميع كائنات Java قد انتظر () وإخطار () وهل هذا يتسبب في ضرب الأداء؟

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

  •  22-07-2019
  •  | 
  •  

سؤال

كل جافا Object لديه الأساليب wait() و notify() (ومتغيرات إضافية). لم أستخدمها أبدًا وأظن أن العديد من الآخرين لم يفعلوا ذلك. لماذا هذه أساسية لدرجة أن كل كائن يجب أن يكون له وهل هناك أداء في الحصول عليها (من المفترض أن يتم تخزين بعض الدول فيها)؟

تعديل للتأكيد على السؤال. إذا كان لدي List<Double> مع 100000 عنصر ثم كل Double لديه هذه الطرق كما تمتد من Object. ولكن يبدو من غير المحتمل أن يعرف كل هذه الأشياء عن المواضيع التي تدير List.

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

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

المحلول

حسنًا ، هذا يعني أن كل كائن لديه يحتمل لديك شاشة مرتبطة به. يتم استخدام نفس الشاشة ل synchronized. إذا كنت تتفق مع قرار أن تكون قادرًا على المزامنة على أي كائن ، فعندئذٍ wait() و notify() لا تضيف المزيد من الحالة لكل كائن. يجوز لـ JVM تخصيص الشاشة الفعلية بتكاسل (أعرف .NET DO) ولكن يجب أن يكون هناك مساحة تخزين متاحة للتحدث عن الشاشة المرتبطة بالكائن. من المسلم به أنه من الممكن أن يكون هذا كمية صغيرة جدًا (على سبيل المثال 3 بايت) والتي لن تنقذ أي ذاكرة على أي حال بسبب حشوة بقية الكائن العلوي - يجب أن تنظر في كيفية تعامل كل فرد من فرد JVM ليقول ليقول ليقول ليقول ليقول ليقول لقوله ليقول بالتأكيد.

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

أنا شخصياً أشعر أن كلا من .NET و Java ارتكبوا خطأ من خلال ربط شاشة مع كل كائن - أفضل أن يكون لدي كائنات تزامن صريحة بدلاً من ذلك. كتبت أكثر قليلاً عن هذا في مدونة منشور حول إعادة تصميم java.lang.object/system.object.

نصائح أخرى

لماذا هذه أساسية لدرجة أن كل كائن يجب أن يكون له وهل هناك أداء في الحصول عليها (من المفترض أن يتم تخزين بعض الدول فيها)؟

TL ؛ DR: فهي طرق سلامة الخيط ولها تكاليف صغيرة بالنسبة لقيمتها.

الحقائق الأساسية التي هذه الطرق الدعم هو:

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

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

من ناحية أخرى ، يمكنني استخدام objectWithMonitor.notifyAll() للسماح لخيوط تنتظر الشاشة تعرف أنني سأتخلى عن الشاشة قريبًا. لا يمكنهم بالفعل المضي قدمًا حتى أغادر الكتلة المتزامنة.

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

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

المتابعة رداً على السؤال المتعلق بكائنات الشاشة الصريحة مقابل الكائنات الصريحة:

اجابة قصيرة: jonskeet: نعم ، سيؤدي إزالة الشاشات إلى خلق مشاكل: سيؤدي إلى خلق الاحتكاك. الحفاظ على هذه الشاشات في Object يذكرنا أن هذا دائماً نظام متعدد مؤشرات الترابط.

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

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

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

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

Punchline: باستخدام طرق التزامن الأساسية ، يمكنك استغلال جزء كبير من الأداء الذي تم تمكينه من قبل المعالجات المتعددة النواة الحديثة مع سلامة مؤشرات الترابط وبدون الكثير من النفقات العامة.

جميع الكائنات في جافا لها شاشات مرتبطة بها. تعتبر بدائل التزامن مفيدة في جميع التعليمات البرمجية متعددة الخيوط ، ومن الجيد جدًا أن تتم مزامنتها على الكائن (الكائنات) التي تصل إليها بدلاً من الكائنات "الشاشة" المنفصلة.

قد تخصص Java الشاشات المرتبطة بالكائنات حسب الحاجة - كما يفعل .NET - وعلى أي حال ، فإن النفقات العامة الفعلية لتخصيص القفل (ولكن عدم استخدامه) سيكون صغيرًا جدًا.

باختصار: من المريح حقًا تخزين الكائنات مع بتات دعم السلامة في مؤشرات الترابط ، وهناك تأثير كبير جدًا في الأداء.

هذه الطرق موجودة لتنفيذ التواصل بين الخيوط.

يفحص هذه المقالة حول هذا الموضوع.

قواعد لتلك الأساليب ، مأخوذة من تلك المقالة:

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

أتمنى أن يساعدك هذا...

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