"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > لماذا يستعيد مؤشر ترابط واحد دائمًا قفل الكائن بعد إعلام () أو إعلام الكل ()؟

لماذا يستعيد مؤشر ترابط واحد دائمًا قفل الكائن بعد إعلام () أو إعلام الكل ()؟

تم النشر بتاريخ 2024-11-16
تصفح:615

Why Does One Thread Always Reacquire the Object Lock After notify() or notifyAll()?

الفرق الدقيق بين notify () و notifyAll ()

في حين أن الفرق الأساسي بين notify () و notifyAll () يكمن في عدد الخيوط المنتظرة التي يتم إيقاظها (واحد مقابل الكل)، وهذا يثير سؤالاً آخر:

لماذا يقوم مؤشر ترابط واحد دائمًا بإعادة الحصول على الكائن lock?

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

الحاجة إلى notifyAll ()

ومع ذلك، باستخدام notify () في سيناريوهات معينة يمكن أن يؤدي إلى طريق مسدود، كما هو موضح في المثال التالي:

فئة المنتج/المستهلك مع يخطر ()

public class ProducerConsumer {

    private final int MAX_SIZE = 1;  // Buffer size

    private List buf = new ArrayList();

    public synchronized void put(Object o) {
        while (buf.size() == MAX_SIZE) {
            wait();
        }
        buf.add(o);
        notify();
    }

    public synchronized Object get() {
        while (buf.size() == 0) {
            wait();
        }
        Object o = buf.remove(0);
        notify();
        return o;
    }
}

سيناريو حالة الجمود:

    يضع المنتج P1 كائنًا في المخزن المؤقت.
  1. يحاول المنتج P2 وP3 وضع الكائنات ولكنهما تم حظره لأن المخزن المؤقت ممتلئ.
  2. يحاول المستهلك C1 الحصول على كائن من المخزن المؤقت.
  3. C1 هو تنفيذ والحصول على الكائن، ثم يخطر مؤشر ترابط الانتظار.
  4. يمكن إيقاظ P2 أو C2 من خلال الإشعار، ولكن تم حظرهما أثناء محاولة إعادة الحصول على القفل.
  5. C3 أيضًا تم حظر محاولة الحصول على القفل.
ونتيجة لذلك، تنتظر المواضيع الثلاثة إلى أجل غير مسمى، مما يؤدي إلى طريق مسدود.

الحل: notifyAll()

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

توصية:

بالنسبة لمعظم السيناريوهات، فإن notifyAll() هي الطريقة المفضلة لأنها تتجنب حالات التوقف التام المحتملة. إذا كان السيناريو المحدد يتطلب تنبيه مؤشر ترابط انتظار محدد واحد فقط، فيمكن استخدام notify() بحذر.

أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3