Domanda

Ho un 2 processi da eseguire nella mia applicazione swing, uno per riempire una lista, e uno a fare operazioni su ogni elemento della lista. Ho appena trasferito i 2 processi in discussioni SwingWorker per fermare la GUI bloccarsi mentre i compiti vengono eseguiti, e perché ho bisogno di fare questo insieme di operazioni per più liste, quindi la concorrenza non sarebbe una cattiva idea, in primo posto. Tuttavia, quando ho appena eseguito

  

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

il filo doStuffToList per riceve la lista vuota (duh ...). Come faccio a dire il secondo processo di aspettare fino a quando il primo è fatto? Suppongo che ho potuto solo nido il secondo processo, alla fine del primo, ma non so, sembra che una cattiva pratica.

È stato utile?

Soluzione

Qualcosa di simile avrebbe fatto, penso?

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

Altri suggerimenti

  

Come faccio a dire il secondo processo di aspettare fino a quando il primo è fatto? Suppongo che ho potuto solo nido il secondo processo, alla fine del primo, ma non so, sembra che una cattiva pratica.

Hai guardato in utilizzando callable e futuro, invece? Suonano come una buona partita per questo genere di cose (lasciare il lavoro doStuffToList su un Future.get () al posto della lista attuale, così sarà pronto quando viene chiamato get), oltre a tutta la faccenda SwingWorker .. ( Consideriamo questo un suggerimento, piuttosto che una risposta)

Abbiamo qualcosa di simile:

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

Questo è abbastanza semplice, IMO, perché nel nostro caso lo SwingWorkerExecutor contiene in realtà tutto il duro da capire cose:

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

Ci sono alcune interfacce mancanti che dovrebbero essere abbastanza straight-forward di scrivere senza vederli qui.

Il nostro SwingWorkerExecutor distribuzione reale esegue utilizzando un ExecutorService iniettato al posto di quella di default (questo riduce il numero di pool di thread di cui abbiamo bisogno per una singola applicazione.) Ma la vera ragione abbiamo introdotto SwingWorkerExecutor era che semplifica e uniforma il trattamento dei SwingWorker il successo e le condizioni di errore e permette anche di sostituire la logica per i test unitari (che, come sono sicuro che si sa, sono molto più semplice se sono a thread singolo.) come si può vedere c'è un mucchio di testo standard che normalmente bisogno per ogni singolo SwingWorker all'interno fatto (), quindi invece di fare questo, abbiamo fatto spostare il () lavorare in un callback.

Il lato-beneficio è che cose come l'esecuzione di più lavoratori a battente in una catena diventano abbastanza facile da implementare.

Per eseguire due processi in sequenza, tradizionalmente basta chiamare un metodo dopo l'altro (!).

fillList();
doStuffToList();

O forse qualcosa di simile:

doStuffToList(fillList());

Se si sta elaborando uno alla volta, si potrebbe desiderare due thread con BlockingQueue mezzo. Si potrebbe andare oltre, avere più thread do-roba.

Per quanto riguarda la Discussione AWT Event Dispatch (EDT) è preoccupato è solo scorporata un'azione senza bloccare, e otterrà una notifica in seguito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top