سؤال

لدي عمليات 2 تؤديها في تطبيق Swing الخاص بي، واحدة لملء قائمة، وواحد للقيام بعمليات في كل عنصر في القائمة. لقد نقلت للتو العمليات 2 إلى مؤشرات ترابط Swingworker لإيقاف قفل واجهة المستخدم الرسومية أثناء إجراء المهام، ولأنني سأحتاج إلى القيام بهذه المجموعة من العمليات إلى عدة قوائم، لذلك لن تكون التزامن فكرة سيئة في الأول مكان. ومع ذلك، عندما ركضت للتو

FillList.execute ()؛
dostufftolist.execute ()؛

خيط dostufftolist لخريطة على القائمة الفارغة (DUH ...). كيف أقول العملية الثانية للانتظار حتى يتم أول واحد؟ أفترض أنني يمكن أن عش العملية الثانية فقط في نهاية أول واحد، لكنني لا دنو، يبدو الأمر بممارسة سيئة.

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

المحلول

شيء من هذا القبيل من شأنه أن يفعل ذلك، على ما أعتقد؟

boolean listIsFull=false;
class FillListWorker extends SwingWorker<Foo,Bar>
{
    ...
    protected void done()
    {
        synchronized (listYouveBeenFilling)
        {
            listIsFull=true;
            listYouveBeenFilling.notifyAll();
        }
    }
    ...
}

class DoStuffToListListWorker extends SwingWorker<Foo,Bar>
{
    ...
    protected Foo doInBackground()
    {
        synchronized (listYouveBeenFilling)
        {
            while (!listIsFull)
            {
                try
                {
                    listYouveBeenFilling.wait();
                }
                catch (InterruptedException ie)
                {
                    // Don't worry, we'll just wait again
                }
            }
        }
    }
    ...
}

نصائح أخرى

كيف أقول العملية الثانية للانتظار حتى يتم أول واحد؟ أفترض أنني يمكن أن عش العملية الثانية فقط في نهاية أول واحد، لكنني لا دنو، يبدو الأمر بممارسة سيئة.

هل نظرت إلى استخدام CAMABLES & الآجلة بدلا من ذلك؟ يبدو أنهم يبدوونا مثل مباراة جيدة لهذا النوع من الأشياء (يتيح dostftolist العمل على مستقبل .. النظر في هذا الاقتراح بدلا من الإجابة)

لدينا شيء من هذا القبيل:

private SwingWorkerExecutor swingWorkerExecutor;

//...

protected void runChain(List<SwingWorker<Void>> chainWorkers,
                        final SwingWorkerExecutor.RunAfter<Void> runAfter,
                        final SwingWorkerExecutor.RunOnError runOnError)
{
    final List<SwingWorker<Void>> remainingWorkers =
        chainWorkers.subList(1, chainWorkers.size());
    SwingWorkerExecutor.RunAfter<Void> chainRunAfter;
    if (chainWorkers.size() > 1)
    {
        chainRunAfter = new SwingWorkerExecutor.RunAfter<Void>()
        {
            @Override
            public void run(Void value)
            {
                runChain(remainingWorkers, runAfter, runOnError);
            }
        };
    }
    else
    {
        chainRunAfter = runAfter;
    }

    currentWorker = chainWorkers.get(0);

    swingWorkerExecutor.execute(currentWorker, chainRunAfter, runOnError);
}

هذا بسيط جدا، IMO، لأنه في حالتنا، يحتوي SwingworkerExutor فعلا على جميع الصعب فهم الأشياء:

public class DefaultSwingWorkerExecutor implements SwingWorkerExecutor
{
    @Override
    public <T> void execute(SwingWorker<T, ?> worker, RunAfter<T> after,
                            RunOnError onError)
    {
        worker.addPropertyChangeListener(
            new RunAfterHandler<T>(worker, after, onError));
        worker.execute();
    }

    private static class RunAfterHandler<T> implements PropertyChangeListener
    {
        private final SwingWorker<T, ?> worker;
        private final RunAfter<T> after;
        private final RunAfter<Throwable> onError;

        protected RunAfterHandler(SwingWorker<T, ?> worker, RunAfter<T> after,
                                  RunOnError onError)
        {
            this.worker = worker;
            this.after = after;
            this.onError = onError;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt)
        {
            if ("state".equals(evt.getPropertyName()) &&
                evt.getNewValue() == SwingWorker.StateValue.DONE)
            {
                if (worker.isCancelled())
                {
                    return;
                }

                try
                {
                    after.run(worker.get());
                }
                catch (InterruptedException e)
                {
                    Thread.currentThread().interrupt();
                }
                catch (ExecutionException e)
                {
                    onError.run(e);
                }
            }
        }
    }
}

هناك بعض الواجهات المفقودة التي يجب أن تكون مستقيما إلى الأمام للكتابة دون رؤيتها هنا.

ينفذ النشر الحقيقي الخاص بنا Swingworkerexecutor باستخدام تقييد منفذ حقن بدلا من الافتراضي (هذا يقلل من عدد تجمعات الخيط التي نحتاج إليها للحصول على تطبيق واحد.) لكن السبب الحقيقي الذي أدخلناهما على التأرجح هو أنه يبسط وتعزيز التعامل مع نجاح Swingworker والنجاح والخطأ شروط وتسمح أيضا باستبدال المنطق لاختبارات الوحدات (والتي، كما أنا متأكد من أنك تعرف، أكثر بساطة إذا كانت خيوط واحدة.) كما ترون أن هناك مجموعة من المراجع التي ستتحتاج إليها عادة لكل عملية سابقة واحدة داخل القيام به ()، لذلك بدلا من القيام بذلك، نتحرك القيام به () العمل () في رد الاتصال.

الفائدة الجانبية هي أن الأمور مثل تشغيل عمال التأرجح المتعدد في سلسلة تصبح سهلة التنفيذ.

لأداء عمليين بالتتابع بالتتابع، يمكنك فقط استدعاء طريقة واحدة بعد الآخر (!).

fillList();
doStuffToList();

أو ربما شيء مثل:

doStuffToList(fillList());

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

فيما يتعلق مؤشر ترابط إرسال الأحداث AWT (EDT)، تشعر بالقلق من إيقاف العمل دون حظره، وسيتم إخطاره لاحقا.

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