Question

J'ai deux processus pour exécuter dans mon application swing, un pour remplir une liste, et un pour effectuer des opérations sur chaque élément sur la liste. Je viens d'emménager les 2 processus en fils SwingWorker pour arrêter l'interface graphique de verrouillage pendant que les tâches sont exécutées, et parce que je dois faire cette série d'opérations à plusieurs listes, donc ne serait pas concurrency une mauvaise idée dans le premier endroit. Cependant, quand je viens de rencontrer

  

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

le fil doStuffToList à ran sur la liste vide (duh ...). Comment puis-je dire le deuxième processus d'attendre jusqu'à ce que le premier se fait? Je suppose que je pouvais imbriquer le deuxième processus à la fin de la première, mais je ne sais pas, il semble que les mauvaises pratiques.

Était-ce utile?

La solution

Quelque chose comme ça le ferait, je pense?

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

Autres conseils

  

Comment puis-je dire le deuxième processus d'attendre jusqu'à ce que le premier se fait? Je suppose que je pouvais imbriquer le deuxième processus à la fin de la première, mais je ne sais pas, il semble que les mauvaises pratiques.

Avez-vous regardé en utilisant Callables à terme au lieu? Ils sonnent comme un bon match pour ce genre de chose (en laissant le travail doStuffToList sur un Future.get () au lieu de la liste réelle, donc il sera prêt quand get est appelé), en dehors de toute entreprise SwingWorker .. ( Considérez ceci une suggestion plutôt qu'une réponse)

Nous avons quelque chose comme ceci:

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

Ceci est assez simple, l'OMI, parce que dans notre cas, le SwingWorkerExecutor contient en fait toutes les choses difficile à comprendre:

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

Il y a quelques interfaces manquantes qui devraient être assez simple d'écrire sans les voir ici.

Notre SwingWorkerExecutor réel de déploiement exécute en utilisant un lieu ExecutorService injecté de la valeur par défaut un (ce qui réduit le nombre de pools de threads dont nous avons besoin pour une seule application.) Mais la vraie raison, nous avons introduit SwingWorkerExecutor est qu'il simplifie et standardise la gestion des SwingWorker succès et les conditions d'erreur et permet également de remplacer la logique pour les tests unitaires (qui, je suis sûr que vous le savez, sont beaucoup plus simples si elles sont un seul thread.) comme vous pouvez le voir il y a un tas de boilerplate vous auriez normalement besoin de chaque SwingWorker intérieur fait (), donc au lieu de le faire, nous faisons bouger le fait () travailler dans un rappel.

Le côté-avantage est que les choses comme la course plusieurs travailleurs Swing dans une chaîne deviennent assez facile à mettre en œuvre.

Pour effectuer deux processus de manière séquentielle, vous appelez simplement traditionnellement une méthode après l'autre (!).

fillList();
doStuffToList();

Ou peut-être quelque chose comme:

doStuffToList(fillList());

Si vous traitez un à la fois, vous voudrez peut-être deux fils avec un BlockingQueue entre. Vous pouvez aller plus loin en plusieurs threads do-stuff.

En ce qui concerne la discussion AWT Dispatch Event (EDT) est concerné, il est juste essaimé une action sans blocage, et être averti plus tard.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top