Java 调度Swingworker线程

Java 调度Swingworker线程,java,swing,concurrency,scheduling,swingworker,Java,Swing,Concurrency,Scheduling,Swingworker,我在swing应用程序中有两个进程要执行,一个用来填充列表,另一个用来对列表中的每个元素执行操作。我刚刚将这两个进程移动到Swingworker线程中,以在执行任务时停止GUI锁定,因为我需要对多个列表执行这组操作,所以并发性一开始不是个坏主意。然而,当我刚刚跑的时候 execute()doStuffToList.execute() 要在空列表上运行的DostufftToList线程(duh…)。如何告诉第二个进程等待第一个进程完成?我想我可以将第二个过程嵌套在第一个过程的末尾,但我不知道,这似

我在swing应用程序中有两个进程要执行,一个用来填充列表,另一个用来对列表中的每个元素执行操作。我刚刚将这两个进程移动到Swingworker线程中,以在执行任务时停止GUI锁定,因为我需要对多个列表执行这组操作,所以并发性一开始不是个坏主意。然而,当我刚刚跑的时候

execute()
doStuffToList.execute()


要在空列表上运行的DostufftToList线程(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
                }
            }
        }
    }
    ...
}
boolean listIsFull=false;
类FillListWorker扩展SwingWorker
{
...
受保护的void done()
{
已同步(listYouveBeenFilling)
{
listIsFull=true;
listYouveBeenFilling.notifyAll();
}
}
...
}
类DostUffToListWorker扩展SwingWorker
{
...
受保护的Foo doInBackground()
{
已同步(listYouveBeenFilling)
{
而(!listIsFull)
{
尝试
{
listYouveBeenFilling.wait();
}
捕获(中断异常ie)
{
//别担心,我们会再等的
}
}
}
}
...
}

要按顺序执行两个过程,传统上只需依次调用一个方法(!)

或者类似于:

doStuffToList(fillList());
如果一次处理一个线程,则可能需要两个线程之间有
BlockingQueue
。您可以通过使用多个do-stuff线程来更进一步

就AWT事件调度线程(EDT)而言,它只是在没有阻塞的情况下派生了一个操作,稍后将收到通知

如何告诉第二个进程等待第一个进程完成?我想我可以将第二个过程嵌套在第一个过程的末尾,但我不知道,这似乎是一种不好的做法


你有没有考虑过改用callables&futures?除了swingworker的整个业务之外,它们听起来很适合这类事情(让DostufftToList在将来处理.get()而不是实际的列表,这样在调用get时就可以准备好了)。。(认为这是一个建议而不是答案)

我们有这样的建议:

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);
}
私人SwingWorkerExecutor SwingWorkerExecutor;
//...
受保护的无效运行链(列出链工人,
最终SwingWorkerExecutor.RunAfter RunAfter,
最终SwingWorkerExecutor.RunOnError(运行错误)
{
剩下的工人名单=
子列表(1,chainWorkers.size());
SwingWorkerExecutor.RunAfter chainRunAfter;
如果(chainWorkers.size()>1)
{
chainRunAfter=新SwingWorkerExecutor.RunAfter()
{
@凌驾
公共作废运行(作废值)
{
runChain(剩余工人、runAfter、RunError);
}
};
}
其他的
{
chainRunAfter=runAfter;
}
currentWorker=chainWorkers.get(0);
执行(currentWorker、chainRunAfter、runOnError);
}
这很简单,因为在我们的例子中,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);
                }
            }
        }
    }
}
public类DefaultSwingWorkerExecutor实现SwingWorkerExecutor
{
@凌驾
公共作废执行(SwingWorker worker、RunAfter、,
运行错误(错误)
{
worker.addPropertyChangeListener(
新的RunAfterHandler(worker、after、onError));
worker.execute();
}
私有静态类RunAfterHandler实现PropertyChangeListener
{
私人最终SwingWorker工人;
私人最终追杀;
私人最终运行后报告;
受保护的RunAfterHandler(SwingWorker worker、RunAfter、,
运行错误(错误)
{
这个工人=工人;
this.after=after;
this.onError=onError;
}
@凌驾
公共作废属性更改(属性更改事件evt)
{
if(“state”.equals(evt.getPropertyName())&&
evt.getNewValue()=SwingWorker.StateValue.DONE)
{
if(worker.isCancelled())
{
返回;
}
尝试
{
after.run(worker.get());
}
捕捉(中断异常e)
{
Thread.currentThread().interrupt();
}
捕获(执行例外)
{
错误运行(e);
}
}
}
}
}
这里有一些缺少的接口,在这里看不到它们的情况下,编写这些接口应该非常简单

我们真正的部署SwingWorkerExecutor使用注入的ExecutorService而不是默认的ExecutorService执行(这减少了单个应用程序所需的线程池数量)但我们引入SwingWorkerExecutor的真正原因是它简化并标准化了SwingWorker成功和错误条件的处理,还允许替换单元测试的逻辑(我相信您知道,如果是单线程的话,那么单元测试的逻辑要简单得多)正如您所看到的,done()中的每个SwingWorker通常都需要一堆样板文件,因此我们将done()工作移到回调中,而不是这样做


另一个好处是,像在一个链中运行多个Swing Worker这样的操作变得非常容易实现。

听起来阻塞队列可能会有所帮助
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);
                }
            }
        }
    }
}