调度Swingworker线程

时间:2009-05-27 14:00:30

标签: java swing concurrency scheduling swingworker

我在swing应用程序中执行了2个进程,一个用于填充列表,另一个用于对列表中的每个元素执行操作。我刚刚将2个进程移动到Swingworker线程中,以便在执行任务时停止GUI锁定,并且因为我需要对多个列表执行这组操作,因此并发性在第一个中并不是一个坏主意地点。但是,当我刚跑完

  

fillList.execute();
doStuffToList.execute();

在空列表上运行的doStuffToList线程(duh ...)。如何判断第二个进程要等到第一个进程完成?我想我可以在第一个过程结束时嵌套第二个过程,但我不知道,这似乎是不好的做法。

4 个答案:

答案 0 :(得分:1)

这样的事情可以做到,我想?

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
                }
            }
        }
    }
    ...
}

答案 1 :(得分:1)

  

如何判断第二个进程要等到第一个进程完成?我想我可以在第一个过程结束时嵌套第二个过程,但我不知道,这似乎是不好的做法。

你有没有考虑过使用callables&amp;期货呢?它们听起来像是这种事情的一个很好的匹配(让doStuffToList工作在Future.get()而不是实际的列表,因此除了整个swingworker业务之外,它将在调用get时准备就绪)。(考虑这个建议而不是答案)

答案 2 :(得分:0)

我们有这样的事情:

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,因为在我们的案例中,SwingWorkerExecutor实际上包含了所有难以理解的东西:

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使用注入的ExecutorService而不是默认的执行来执行(这减少了我们为单个应用程序所需的线程池数量。)但我们引入SwingWorkerExecutor的真正原因是它简化并标准化了SwingWorker的处理成功和错误条件,也允许替换单元测试的逻辑(正如我相信,如果它们是单线程的话,它们会更简单。)正如你所看到的,你通常需要一堆样板文件。每个SwingWorker都在done()里面,所以我们将done()工作移到回调中。

另一个好处是,在链中运行多个Swing worker的事情变得非常容易实现。

答案 3 :(得分:-1)

要按顺序执行两个进程,传统上你只需要调用一个方法(!)。

fillList();
doStuffToList();

或者类似的东西:

doStuffToList(fillList());

如果您一次处理一个,则可能需要两个BlockingQueue之间的线程。你可以通过多个do-stuff线程来进一步发展。

就AWT事件调度线程(EDT)而言,它只是在没有阻塞的情况下分离出一个动作,并会在稍后得到通知。