خيوط المعالجة المتعددة: كائنات يتم تعيين إلى فارغة في حين استخدامها

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

سؤال

ولدي التطبيق صغير يحتوي على تجسيد الموضوع. كل هذا الموضوع لا هو رسم الأشياء لي في موقعهم الحالي.

ولدي بعض التعليمات البرمجية مثل:

public void render()
{
    // ... rendering various objects

    if (mouseBall != null) mouseBall.draw()

}

وبعد ذلك ولدي أيضا بعض معالج الفأر الذي يخلق ويحدد mouseBall في الكرة الجديدة عندما يقوم المستخدم بالنقر فوق الماوس. يمكن للمستخدم ثم اسحب الماوس حول والكرة سوف تتبع أين يذهب الماوس. عندما يطلق المستخدم الكرة لدي الحدث الماوس آخر أن يحدد mouseBall = فارغة.

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

ما هو الحل لمشكلة مثل هذا؟

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

المحلول

والمشكلة تكمن في حقيقة أن يمكنك الوصول mouseBall مرتين، مرة واحدة للتحقق ما إذا كان لا null وآخر لاستدعاء دالة على ذلك. يمكنك تجنب هذه المشكلة باستخدام مؤقت مثل هذا:

public void render()
{
    // ... rendering various objects
    tmpBall = mouseBall;
    if (tmpBall != null) tmpBall.draw();
}

نصائح أخرى

لديك لمزامنة إذا ورسم البيانات بحيث فهي مضمونة ليتم تشغيلها كما تسلسل ذري واحد. في جافا، وهذا من شأنه أن يتم مثل ذلك:

    
public void render()
{
    // ... rendering various objects
    synchronized(this) {
        if (mouseBall != null) mouseBall .draw();
   }
}

وأنا أعلم أنك قد قبلت بالفعل إجابات أخرى، ولكن خيار ثالث يتمثل في استخدام الطبقة AtomicReference حزمة java.util.concurrent.atomic ل. وهذا يوفر استرجاع وتحديث ومقارنة العمليات التي تعمل بالذرة دون أن تحتاج إلى أي رمز الداعمة. حتى في المثال الخاص بك:

public void render()
{
    AtomicReference<MouseBallClass> mouseBall = ...;

    // ... rendering various objects
    MouseBall tmpBall = mouseBall.get();
    if (tmpBall != null) tmpBall.draw();
}

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

وبناء على ذلك المثال المحدد المستخدمة هنا ليست جيدة لإظهار قوة AtomicReferences. النظر بدلا من ذلك بأن ما تتمتعون به موضوع آخر سيتم تحديث vairable mouseball إلا إذا كان بالفعل باطل - وهو تعبير مفيد لمختلف الكتل على غرار initialisation من التعليمات البرمجية. في هذه الحالة، فإنه عادة ما تكون ضرورية لاستخدام تزامن، لضمان أن إذا دققت وجدت كانت الكرة فارغة، فإنه <م> لا تزال تعتبر باطلة عندما حاولت تعيين (وإلا كنت مرة أخرى في نواحي المشكلة الأصلية). ومع ذلك، مع AtomicReference يمكنك ببساطة يقول:

mouseBall.compareAndSet(null, possibleNewBall);

ولأن هذا هو عملية ذرية، حتى إذا كان موضوع واحد "يرى" القيمة كما فارغة فإنه أيضا تعيين ذلك إلى الإشارة possibleNewBall قبل أي مواضيع أخرى الحصول على فرصة لقراءته.

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

   MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
   // Cleanup code using oldBall

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

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