Java Blockingqueue ليس لديه نظرة خاطفة على منع؟
-
20-09-2019 - |
سؤال
لدي طابور حظر للكائنات.
أريد أن أكتب موضوعًا يحظر حتى يكون هناك كائن في قائمة الانتظار. على غرار الوظائف التي توفرها blockingqueue.take ().
ومع ذلك ، بما أنني لا أعرف ما إذا كنت سأتمكن من معالجة الكائن بنجاح ، فأنا أريد فقط إلقاء نظرة خاطفة على () وعدم إزالة الكائن. أريد إزالة الكائن فقط إذا كنت قادرًا على معالجته بنجاح.
لذلك ، أود الحصول على وظيفة نظرة خاطفة. حاليًا ، يعود Peek () إذا كان قائمة الانتظار فارغة وفقًا لـ Javadocs.
هل فاتني شيء؟ هل هناك طريقة أخرى لتحقيق هذه الوظيفة؟
تعديل:
أي أفكار حول ما إذا كنت قد استخدمت للتو قائمة انتظار آمنة للخيط وألقيت نظرة خاطفة ونمت بدلاً من ذلك؟
public void run() {
while (!exit) {
while (queue.size() != 0) {
Object o = queue.peek();
if (o != null) {
if (consume(o) == true) {
queue.remove();
} else {
Thread.sleep(10000); //need to backoff (60s) and try again
}
}
}
Thread.sleep(1000); //wait 1s for object on queue
}
}
لاحظ أن لدي فقط موضوع مستهلك واحد وخيط منتج واحد (منفصل). أعتقد أن هذا ليس فعالًا مثل استخدام blockingqueue ... أي تعليقات موضع تقدير.
المحلول
يمكنك استخدام أ LinkedBlockingDeque وإزالة العنصر جسديًا من قائمة الانتظار (باستخدام takeLast()
) لكن استبدله مرة أخرى في نهاية قائمة الانتظار إذا فشلت المعالجة في استخدام putLast(E e)
. في هذه الأثناء ، سيضيف "المنتجون" عناصر إلى أمامي من قائمة الانتظار باستخدام putFirst(E e)
.
يمكنك دائمًا تغليف هذا السلوك داخلك Queue
التنفيذ وتقديم أ blockingPeek()
الطريقة التي تؤدي takeLast()
تليها putLast()
وراء الكواليس على LinkedBlockingDeque
. وبالتالي من وجهة نظر عميل الاتصال ، لا تتم إزالة العنصر أبدًا من قائمة الانتظار الخاصة بك.
نصائح أخرى
ومع ذلك ، بما أنني لا أعرف ما إذا كنت سأتمكن من معالجة الكائن بنجاح ، فأنا أريد فقط إلقاء نظرة خاطفة على () وعدم إزالة الكائن. أريد إزالة الكائن فقط إذا كنت قادرًا على معالجته بنجاح.
بشكل عام ، ليس آمنًا للخيط. ماذا لو ، بعدك peek()
وتحديد أنه يمكن معالجة الكائن بنجاح ، ولكن أمامك take()
لإزالة ومعالجة ، يأخذ موضوع آخر هذا الكائن؟
الشيء الوحيد الذي أعرفه بذلك حلق في مجموعات Apache Commons:
إذا تم استدعاء إما الحصول على أو إزالة على مخزن مؤقت فارغ ، فإن مؤشر ترابط الاتصال ينتظر الإخطار بأن عملية إضافة أو ADDALL قد اكتملت.
get()
يعادل peek()
, ، و Buffer
يمكن أن تصنع لتصرف مثل BlockingQueue
عن طريق تزيين أ غير محدود مع BlockingBuffer
هل يمكنك أيضًا إضافة قائمة انتظار مستمع حدث إلى قائمة انتظار الحظر الخاصة بك ، ثم عند إضافة شيء ما إلى قائمة انتظار (الحظر) ، أرسل حدثًا إلى مستمعيك؟ يمكن أن يكون لديك كتلة مؤشر الترابط حتى تم استدعاء طريقة ActionPerformed.
الجواب السريع هو ، ليس هناك طريقة حقًا لإلقاء نظرة خاطفة على الحظر ، حيث يقوم شريط بتنفيذ قائمة انتظار الحظر مع نظرة خاطفة على الحجب () بنفسك.
هل فاتني شيء؟
يمكن أن تكون نظرة خاطفة () مزعجة مع التزامن -
- إذا لم تتمكن من معالجة رسالة نظرة خاطفة () "، فسيتم تركها في قائمة الانتظار ، إلا إذا كان لديك العديد من المستهلكين.
- من الذي سيقوم بإخراج هذا الكائن من قائمة الانتظار إذا لم تتمكن من معالجته؟
- إذا كان لديك العديد من المستهلكين ، فستحصل على شرط سباق بينك وبينه وخيط آخر معالجة عناصر ، مما يؤدي إلى معالجة مكررة أو أسوأ.
يبدو أنك قد تكون أفضل حالًا في إزالة العنصر ومعالجته باستخدام أنمط سلسلة المسؤولية
تحرير: Re: مثالك الأخير: إذا كان لديك مستهلك واحد فقط ، فلن تتخلص أبدًا من الكائن الموجود في قائمة الانتظار - ما لم يتم تحديثه في الوقت المناسب - وفي هذه الحالة من الأفضل أن تكون حذرًا جدًا بشأن سلامة الخيط و ربما لا ينبغي أن تضع العنصر في قائمة الانتظار على أي حال.
يبدو أن blockingqueue نفسها لا تملك الوظائف التي تحددها.
قد أحاول إعادة إطار المشكلة قليلاً: ماذا ستفعل مع الأشياء التي لا يمكنك "معالجتها بشكل صحيح"؟ إذا كنت تتركهم فقط في قائمة الانتظار ، فسيتعين عليك سحبها في مرحلة ما والتعامل معهم. سأوصي إما بمعرفة كيفية معالجتها (عادة ، إذا كانت قائمة انتظار. فيفو.
ليس إجابة في حد ذاتها ، ولكن: JDK-6653412 يدعي أن هذه ليست حالة استخدام صالحة.
حل "أبسط"
لا تقم بمعالجة التالي عنصر حتى السابق تتم معالجة العنصر بنجاح.
public void run() {
Object lastSuccessfullyProcessedElement = null;
while (!exit) {
Object obj = lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking
boolean successful = process(obj);
if(!successful) {
lastSuccessfullyProcessedElement = obj;
} else {
lastSuccessfullyProcessedElement = null;
}
}
}
- الدعوة
peek()
والتحقق مما إذا كانت القيمة فارغة غير فعالة.
لقد رأيت استخدام وحدة المعالجة المركزية يذهب إلى 10 ٪ على نظامي عندما يكون قائمة الانتظار فارغة للبرنامج التالي.
while (true) {
Object o = queue.peek();
if(o == null) continue;
// omitted for the sake of brevity
}
مضيفا
sleep()
يضيف بطء.إضافته مرة أخرى إلى قائمة الانتظار باستخدام
putLast
سوف يزعج الأمر. علاوة على ذلك ، إنها عملية حظر تتطلب أقفال.