java swing swingworker cancellation

java - SwingWorker: ¿cuándo exactamente se llama método hecho?



cancellation (6)

Cuando un hilo se cancela a través de

myWorkerThread.cancel(true/false);

El método hecho es (bastante sorprendentemente) llamado por el propio método de cancelación.

Lo que puede esperar que suceda, pero en realidad NO:
- Usted llama cancelar (ya sea con MayInterrupt o no)
- Cancelar configurar la cancelación de hilo
- las salidas doInBackground
- el hecho se llama *
(* lo hecho está en cola para el EDT, eso significa que, si EDT está ocupado, sucede DESPUÉS DE QUE el EDT haya terminado lo que está haciendo)

Lo que realmente sucede:
- Usted llama cancelar (ya sea con MayInterrupt o no)
- Cancelar configurar la cancelación de hilo
- el hecho se llama como parte del código de cancelación *
- el doInBackground saldrá cuando haya terminado su ciclo
(* el hecho no está en cola para la EDT, sino que se invoca en la llamada de cancelación, por lo que tiene un efecto muy inmediato en la EDT, que a menudo es la GUI)

Proporciono un ejemplo simple que prueba esto.
Copiar, pegar y ejecutar.
1. Genero una excepción de tiempo de ejecución dentro de hecho. El hilo de la pila muestra que hecho es llamado por cancelar.
2. Aproximadamente 4 segundos después de la cancelación, recibirás un saludo de doInBackground, que prueba de manera extraña que se hace antes de que salga el hilo.

import java.awt.EventQueue; import javax.swing.SwingWorker; public class SwingWorker05 { public static void main(String [] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { W w = new W(); w.execute(); Thread.sleep(1000); try{w.cancel(false);}catch (RuntimeException rte) { rte.printStackTrace(); } Thread.sleep(6000); } catch (InterruptedException ignored_in_testing) {} } }); } public static class W extends SwingWorker <Void, Void> { @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { Thread.sleep(5000); } System.out.println("I''m still alive"); return null; } @Override protected void done() {throw new RuntimeException("I want to produce a stack trace!");} } }

Javadoc del método done() de SwingWorker:

Ejecutado en el subproceso de distribución de eventos una vez finalizado el método doInBackground.

Tengo pistas de que no es cierto en el caso de un trabajador cancelado.
En cada caso, se llama a Done (terminación o cancelación normal), pero cuando se cancelled , no se pone en cola en la EDT, como ocurre en la terminación normal.

¿Hay algún análisis más preciso sobre cuándo se done llamada en caso de que se cancele un SwingWorker ?

Aclaración: esta pregunta NO es sobre cómo cancel un SwingWorker . Aquí se supone que el SwingWorker se cancela de la manera correcta.
Y NO se trata de que el hilo siga funcionando cuando se supone que están terminados.


Desde la documentación de Java: cancel (boolean mayInterruptIfRunning) "mayInterruptIfRunning - true si el subproceso que ejecuta esta tarea debería interrumpirse; de ​​lo contrario, las tareas en curso se pueden completar"

Si llama a cancelar (verdadero) en lugar de cancelar (falso), eso parece comportarse como está esperando.

No he visto terminado () cancelado el EDT utilizando EventQueue.isDispatchThread ()


En cualquier caso, se llama a done() , ya sea que el trabajador sea cancelado o termine normalmente. Sin embargo, hay casos en los que doInBackground todavía se está ejecutando y el método de done ya se llama (esto se hace dentro de cancel() sin importar si el subproceso ya terminó). Un ejemplo simple se puede encontrar aquí:

public static void main(String[] args) throws AWTException { SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() { protected Void doInBackground() throws Exception { System.out.println("start"); Thread.sleep(2000); System.out.println("end"); return null; } protected void done() { System.out.println("done " + isCancelled()); } }; sw.execute(); try { Thread.sleep(1000); sw.cancel(false); Thread.sleep(10000); } catch (InterruptedException ex) { ex.printStackTrace(); }

Por lo tanto, puede ocurrir que se llame antes de que termine doInBackground .


Hasta que SwingWorker se arregla bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514 Aquí hay una versión simple (probada) con las funciones básicas (similares) y luego SwingWorker

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package tools; import java.util.LinkedList; import java.util.List; import javax.swing.SwingUtilities; /** * * @author patrick */ public abstract class MySwingWorker<R,P> { protected abstract R doInBackground() throws Exception; protected abstract void done(R rvalue, Exception ex, boolean canceled); protected void process(List<P> chunks){} protected void progress(int progress){} private boolean cancelled=false; private boolean done=false; private boolean started=false; final private Object syncprogress=new Object(); boolean progressstate=false; private int progress=0; final private Object syncprocess=new Object(); boolean processstate=false; private LinkedList<P> chunkes= new LinkedList<>(); private Thread t= new Thread(new Runnable() { @Override public void run() { Exception exception=null; R rvalue=null; try { rvalue=doInBackground(); } catch (Exception ex) { exception=ex; } //Done: synchronized(MySwingWorker.this) { done=true; final Exception cexception=exception; final R crvalue=rvalue; final boolean ccancelled=cancelled; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { done(crvalue, cexception, ccancelled); } }); } } }); protected final void publish(P p) { if(!Thread.currentThread().equals(t)) throw new UnsupportedOperationException("Must be called from worker Thread!"); synchronized(syncprocess) { chunkes.add(p); if(!processstate) { processstate=true; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { List<P> list; synchronized(syncprocess) { MySwingWorker.this.processstate=false; list=MySwingWorker.this.chunkes; MySwingWorker.this.chunkes= new LinkedList<>(); } process(list); } }); } } } protected final void setProgress(int progress) { if(!Thread.currentThread().equals(t)) throw new UnsupportedOperationException("Must be called from worker Thread!"); synchronized(syncprogress) { this.progress=progress; if(!progressstate) { progressstate=true; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { int value; //Acess Value synchronized(syncprogress) { MySwingWorker.this.progressstate=false; value=MySwingWorker.this.progress; } progress(value); } }); } } } public final synchronized void execute() { if(!started) { started=true; t.start(); } } public final synchronized boolean isRunning() { return started && !done; } public final synchronized boolean isDone() { return done; } public final synchronized boolean isCancelled() { return cancelled; } public final synchronized void cancel() { if(started && !cancelled && !done) { cancelled=true; if(!Thread.currentThread().equals(t)) t.interrupt(); } } }


SI utiliza return Void: ... @ Override public Void doInBackground () {...

done () se invoca cuando doInBackground () ha finalizado.

SI no usa return Void: ... @ Override public boolean doInBackground () {...

done () se ignora y sabe que ha finalizado porque tiene su devolución.


algo es posible, otro podría ser ilusión

muy bien salido

run: ***removed*** java.lang.RuntimeException: I want to produce a stack trace! at help.SwingWorker05$W.done(SwingWorker05.java:71) at javax.swing.SwingWorker$5.run(SwingWorker.java:717) at javax.swing.SwingWorker.doneEDT(SwingWorker.java:721) at javax.swing.SwingWorker.access$100(SwingWorker.java:207) at javax.swing.SwingWorker$2.done(SwingWorker.java:284) at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293) at java.util.concurrent.FutureTask.cancel(FutureTask.java:76) at javax.swing.SwingWorker.cancel(SwingWorker.java:526) at help.SwingWorker05$1.run(SwingWorker05.java:25) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) I''m still alive Thread Status with Name :SwingWorker1, SwingWorker Status is STARTED SwingWorker by tutorial''s background process has completed Thread Status with Name :SwingWorker1, SwingWorker Status is DONE Thread Status with Name :look here what''s possible with SwingWorker, SwingWorker Status is STARTED BUILD SUCCESSFUL (total time: 10 seconds)

desde

import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.SwingWorker; public class SwingWorker05 { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { W w = new W(); w.addPropertyChangeListener( new SwingWorkerCompletionWaiter("look here what''s possible with SwingWorker")); w.execute(); Thread.sleep(1000); try { w.cancel(false); } catch (RuntimeException rte) { rte.printStackTrace(); } Thread.sleep(6000); } catch (InterruptedException ignored_in_testing) { } } }); final MySwingWorker mySW = new MySwingWorker(); mySW.addPropertyChangeListener(new SwingWorkerCompletionWaiter("SwingWorker1")); mySW.execute(); } private static class MySwingWorker extends SwingWorker<Void, Void> { private static final long SLEEP_TIME = 250; @Override protected Void doInBackground() throws Exception { Thread.sleep(SLEEP_TIME); return null; } @Override protected void done() { System.out.println("SwingWorker by tutorial''s background process has completed"); } } public static class W extends SwingWorker { @Override protected Object doInBackground() throws Exception { while (!isCancelled()) { Thread.sleep(5000); } System.out.println("I''m still alive"); return null; } @Override protected void done() { System.out.println("***remove***"); throw new RuntimeException("I want to produce a stack trace!"); } } private static class SwingWorkerCompletionWaiter implements PropertyChangeListener { private String str; SwingWorkerCompletionWaiter(String str) { this.str = str; } @Override public void propertyChange(PropertyChangeEvent event) { if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) { System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else { System.out.println("Thread Status with Name :" + str + ", Something wrong happends "); } } } }