2009-06-02 16 views
11

Tengo una aplicación oscilante que almacena una lista de objetos. Cuando el usuario hace clic en un botón,Prevenir el bloqueo de la GUI durante una tarea en segundo plano

que desea llevar a cabo dos operaciones en cada objeto en la lista, y luego una vez que se haya completado, gráfico de los resultados en un JPanel. He estado probando SwingWorker, Callable & Runnable para hacer el procesamiento, pero no importa lo que haga, mientras proceso la lista (que puede tardar unos minutos, ya que está enlazado a IO), la GUI está bloqueada.

tengo la sensación de que es probablemente la forma en que estoy llamando a los hilos o algo, o podría ser que ver con la representación gráfica de funciones? Eso no está enhebrado ya que es muy rápido.

que tengo que hacer las dos etapas de procesamiento con el fin también, así que ¿cuál es la mejor manera de asegurar que el segundo ha esperado en la primera? He usado join(), y luego

while(x.isAlive()) 
{ 
     Thread.sleep(1000); 
} 

para tratar de asegurar esto, pero me preocupa que esto podría ser la causa de mi problema también.

que he estado buscando por todas partes para algunas indicaciones, pero como yo no puedo encontrar ninguna estoy seguro de que estoy haciendo algo estúpido aquí.

+2

Podría ser útil incluir algún código que muestre cómo está utilizando SwingWorker. –

+0

de acuerdo; muéstranos el código problemático. – Rob

Respuesta

18

El problema es que su tarea de larga ejecución está bloqueando el subproceso que mantiene la GUI en buen estado.

Lo que tendrá que hacer es colocar la tarea de larga ejecución en otra secuencia.

Algunas formas comunes de hacer esto están utilizando temporizadores o un SwingWorker.

El Java tutorials tienen mucha información con respecto a estas cosas en su lección de concurrencia.

Para asegurarse de que la primera tarea finaliza antes que la segunda, simplemente póngalas ambas en el mismo hilo. De esta forma, no tendrá que preocuparse por mantener dos hilos diferentes sincronizados correctamente.

Aquí está un ejemplo de implementación de un SwingWorkerFor su caso:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> { 
    private List<Object> list 
    public YourClassSwingWorker(List<Object> theOriginalList){ 
     list = theOriginalList; 
    } 

    @Override 
    public List<Object> doInBackground() { 
     // Do the first opperation on the list 
     // Do the second opperation on the list 

     return list; 
    } 

    @Override 
    public void done() { 
     // Update the GUI with the updated list. 
    } 
} 

Para utilizar este código, cuando el evento para modificar la lista es despedido, cree un nuevo SwingWorker y decirle que empezar.

+1

Estoy bastante seguro de que la pregunta ya menciona hilos y SwingWorker. Además, SwingUtilities.invokeLater() ejecuta cosas en el hilo de la GUI. – Powerlord

+0

Sí, le di un poco de respuesta genérica para enhebrar el hilo ... algo apesta – jjnguy

+0

OP aquí, sí, ya probé ambas sugerencias, pero es posible que no las haya implementado correctamente ... He pasado por el tutorial de swing , pero no tiene mucho sobre el trabajador de swing en absoluto, al menos no la información que estoy buscando – Simonw

5

No está devolviendo el hilo de giro correctamente. Me doy cuenta de que estás usando invocable/ejecutable, pero supongo que no lo estás haciendo bien (aunque no publicaste suficiente código para estar seguro).

La estructura básica sería:

swingMethod() { // Okay, this is a button callback, we now own the swing thread 
    Thread t=new Thread(new ActuallyDoStuff()); 
    t.start(); 
} 

public class ActuallyDoStuff() implements Runnable { 
    public void run() { 
     // this is where you actually do the work 
    } 
} 

Esto es justo al lado de la parte superior de mi cabeza, pero supongo que o bien no está haciendo el hilo.start y en lugar de llamar al método de ejecución directamente, o estás haciendo algo más en el primer método que lo bloquea (como thread.join). Ninguno de estos liberaría el hilo de swing. El primer método DEBE regresar rápidamente, el método run() puede tomar todo el tiempo que quiera.

Si está haciendo un thread.join en el primer método, ¡entonces el hilo NO se devuelve al sistema!

Editar: (Segunda edición en realidad) Creo que para hablar sobre el problema que realmente está sintiendo, es posible que desee pensar más en términos de un modelo/vista/sistema de control. El código que está escribiendo es el controlador (la vista generalmente se considera que son los componentes en la pantalla; la vista/el controlador generalmente están muy vinculados).

Cuando su controlador recibe el evento, debe pasar el trabajo a su modelo. La vista está entonces fuera de la imagen. No espera el modelo, simplemente está listo.

Cuando su modelo está terminado, necesita decirle al controlador que haga algo más. Lo hace a través de uno de los métodos de invocación. Esto transfiere el control de regreso al controlador y continúa su camino alegremente. Si lo piensas de esta manera, separar el control y pasarlo deliberadamente hacia adelante y hacia atrás no se siente tan voluminoso, y en realidad es muy común hacerlo de esta manera.

+0

En mi caso yo estaba haciendo thread.run() en lugar de thread.start(), y eso me llevó al bloqueo de la GUI. La configuración de thread.start() resolvió el problema. – Alexey

1

Parece que el problema podría ser que está esperando a que los hilos terminen dentro del hilo de la GUI. La secuencia de la interfaz gráfica de usuario no debe esperar en estos subprocesos; en su lugar, debe hacer que los subprocesos de trabajo invoquen algún método en el subproceso de GUI que establece una marca. Cuando se establecen ambas banderas, entonces sabes que ambos hilos terminaron y puedes hacer el gráfico.

0

Realmente no puedo hablar con el modelo de hilos de swing, pero:

que tengo que hacer las dos etapas de procesamiento con el fin también, así que ¿cuál es la mejor manera de asegurar que el segundo ha esperado en ¿el primero?

Para este tipo de funcionalidad, sugiero que cree dos hilos de trabajo e incruste un intermediario de JMS. Entregue trabajo a los dos hilos pasando mensajes a las colas JMS de las que leen. El hilo de la interfaz gráfica de usuario es libre de examinar las colas para determinar cuándo está sucediendo el trabajo y representar el estado de la interfaz de usuario.

0

La solución a mi problema era una mezcla de jjnguy y las respuestas de Bill K, así que muchas gracias por esos muchachos. Necesitaba usar hilos dentro de un SwingWorker así:

public class Worker extends SwingWorker<Void, Void> 
{ 
    private List<Object> list; 
    public YourClassSwingWorker(List<Object> theOriginalList){ 
     list = theOriginalList; 
    } 

    @Override 
    public List<Object> doInBackground() { 
     Thread t = new Thread(new ProcessorThread(list)); 
     t.start(); 
    } 

    @Override 
    public void done() { 
     // draw graph on GUI 
    } 
} 
class ProcessorThread implements Runnable { 
    //do lots of IO stuff 
    Thread t2 = new Thread(new SecondProcess()); 
    t2.start(); 
} 

Esto hizo que todo el trabajo se está haciendo por los subprocesos de trabajo lejos de la interfaz gráfica de usuario, y también asegurar que la propia SwingWorker no estaba haciendo todo el trabajo , que podría haber sido un problema.

+3

Whoa whoa whoa! ¿Por qué estás generando un hilo del SwingWorker? SwingWorkers (cuando se inició con el método execute()) no se ejecuta en el hilo de la GUI, por lo que no debería haber ninguna razón para crear otro hilo aquí. –

+0

Debo haberlo hecho mal al principio, porque esa era la única solución que me funcionaba – Simonw

Cuestiones relacionadas