Pregunta

Tengo 2 procesos a realizar en mi aplicación swing, uno para llenar una lista, y uno que hacer operaciones en cada elemento de la lista. Me acabo de mudar los 2 procesos en hilos SwingWorker para detener la interfaz gráfica de usuario de bloqueo hacia arriba mientras se realizan las tareas, y porque son necesarias para realizar este conjunto de operaciones a varias listas, por lo que la concurrencia no sería una mala idea en el primer sitio. Sin embargo, cuando acaba de ejecutar

  

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

el hilo doStuffToList a ran en la lista vacía (duh ...). ¿Cómo le digo el segundo proceso que esperar hasta que el primero se hace? Supongo que podría simplemente nido del segundo proceso al final de la primera, pero no sé, parece que las malas prácticas.

¿Fue útil?

Solución

Algo como esto lo haría, creo?

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

Otros consejos

  

¿Cómo le digo el segundo proceso que esperar hasta que el primero se hace? Supongo que podría simplemente nido del segundo proceso al final de la primera, pero no sé, parece que las malas prácticas.

¿Has mirado en el uso de callables y futuros en lugar? Suenan como una buena opción para este tipo de cosas (dejar el trabajo doStuffToList en un Future.get () en lugar de la lista real, por lo que estará listo cuando get se llama), además de todo el negocio SwingWorker .. ( Considere esto una sugerencia en lugar de una respuesta)

Tenemos algo como esto:

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

Esto es bastante simple, la OMI, ya que en nuestro caso el SwingWorkerExecutor en realidad contiene todo el material difícil de entender:

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

Hay algunos la falta de interfaces que deben ser bastante recta hacia adelante para escribir sin verlas aquí.

Nuestra SwingWorkerExecutor despliegue verdadera ejecuta utilizando un ExecutorService inyectada en lugar de la que viene por defecto (esto reduce el número de grupos de subprocesos que necesitamos para una sola aplicación.) Pero la verdadera razón por la que presentamos SwingWorkerExecutor fue que simplifica y estandariza el manejo de SwingWorker el éxito y las condiciones de error y también permite la sustitución de la lógica para pruebas unitarias (que, como estoy seguro que usted sabe, son mucho más simple si son de un solo subproceso.) como se puede ver hay un montón de repetitivo que normalmente se necesita para cada SwingWorker realiza en el interior (), así que en vez de hacer eso, nos mueve el hecho () trabajar en una devolución de llamada.

El beneficio secundario es que cosas como la ejecución de múltiples workers de Swing en una cadena se convierten en bastante fácil de implementar.

Para llevar a cabo dos procesos de forma secuencial, tradicionalmente que acaba de llamar un método detrás de otro (!).

fillList();
doStuffToList();

O tal vez algo como:

doStuffToList(fillList());

Si va a procesar uno a la vez, es posible que desee dos hilos con un BlockingQueue el medio. Es posible ir más allá al tener múltiples hilos do-stuff.

En cuanto a la distribución de eventos AWT rosca (EDT) se refiere es sólo escindió una acción sin bloquear, y recibirá una notificación posterior.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top