سؤال

لدي طابور حظر للكائنات.

أريد أن أكتب موضوعًا يحظر حتى يكون هناك كائن في قائمة الانتظار. على غرار الوظائف التي توفرها 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;
        }
    }
}
  1. الدعوة peek() والتحقق مما إذا كانت القيمة فارغة غير فعالة.

لقد رأيت استخدام وحدة المعالجة المركزية يذهب إلى 10 ٪ على نظامي عندما يكون قائمة الانتظار فارغة للبرنامج التالي.

while (true) {
   Object o = queue.peek();
   if(o == null) continue;
   // omitted for the sake of brevity
}
  1. مضيفا sleep() يضيف بطء.

  2. إضافته مرة أخرى إلى قائمة الانتظار باستخدام putLast سوف يزعج الأمر. علاوة على ذلك ، إنها عملية حظر تتطلب أقفال.

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