خيوط المعالجة المتعددة: كائنات يتم تعيين إلى فارغة في حين استخدامها
-
21-08-2019 - |
سؤال
ولدي التطبيق صغير يحتوي على تجسيد الموضوع. كل هذا الموضوع لا هو رسم الأشياء لي في موقعهم الحالي.
ولدي بعض التعليمات البرمجية مثل:
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 () رائع لليتعارض يشترك فيها العالم بأسره كما يمكنك أن تضمن كل استدعاء فإنه سيعود قيمة متميزة، بغض النظر عن التداخل من المواضيع. سلامة الموضوع مع حد أدنى من ضجة.