Pergunta

Eu tenho um 2 processos para executar no meu aplicativo swing, um para preencher a lista, e um para fazer operações em cada elemento na lista. Acabei de me mudar os 2 processos em tópicos SwingWorker para parar o GUI trancar enquanto as tarefas são executadas, e porque eu precisará fazer este conjunto de operações para várias listas, de modo a concorrência não seria uma má idéia em primeiro Lugar, colocar. No entanto, quando eu corri

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

o fio doStuffToList para correu na lista vazia (duh ...). Como eu digo o segundo processo que esperar até o primeiro é feito? Acho que eu poderia apenas ninho o segundo processo no final do primeiro, mas eu não sei, parece má prática.

Foi útil?

Solução

Algo como isso iria fazê-lo, eu acho?

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

Outras dicas

Como posso dizer ao segundo processo que esperar até o primeiro é feito? Acho que eu poderia apenas ninho o segundo processo no final do primeiro, mas eu não sei, parece má prática.

Você olhou em usar chamáveis ??e futuros em vez disso? Eles soam como um bom jogo para esse tipo de coisa (deixar o trabalho doStuffToList em um Future.get () em vez da lista actual, por isso vai estar pronto quando get é chamado), além de todo o negócio SwingWorker .. ( considere isso uma sugestão em vez de uma resposta)

Temos algo parecido com isto:

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);
}

Isso é muito simples, IMO, porque no nosso caso o SwingWorkerExecutor realmente contém todas as difícil de entender coisas:

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);
                }
            }
        }
    }
}

Existem algumas interfaces desaparecidas que devem ser bem simples para escrever sem vê-los aqui.

Nossos executa SwingWorkerExecutor implantação real usando uma injetado ExecutorService em vez do padrão (o que reduz o número de pools de threads que precisamos para um único app.) Mas a verdadeira razão que introduzimos SwingWorkerExecutor era que simplifica e padroniza a manipulação de SwingWorker sucesso e condições de erro e também permite substituir a lógica para testes de unidade (que, como eu tenho certeza que você sabe, são muito mais simples se eles são único segmento.) como você pode ver, há um monte de clichê que você normalmente precisa para cada SwingWorker dentro feito (), então ao invés de fazer isso, passamos o trabalho feito () em um retorno de chamada.

O lado-benefício é que coisas como a execução de vários trabalhadores do balanço em uma cadeia de tornar-se bastante fácil de implementar.

Para executar dois processos sequencialmente, tradicionalmente, você apenas chamar um método após o outro (!).

fillList();
doStuffToList();

Ou talvez algo como:

doStuffToList(fillList());

Se você estiver processando um de cada vez, você pode querer dois segmentos com um BlockingQueue entre. Você pode ir mais longe por ter vários segmentos do-stuff.

Quanto ao Tópico AWT Despacho do evento (EDT) está em causa é apenas desmembrada uma ação sem bloqueio, e vai ser notificado mais tarde.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top