SwingWorker: cuando exactamente se llama hacer el método?

Javadoc de la done() método de SwingWorker:

Ejecutado en el Envío de Evento Hilo después de que el método doInBackground
está terminado.

He pistas que no es cierto en el caso de cancelado trabajador.

Done se llama en cada caso (normal terminación o cancelación), pero cuando cancelled es no en la cola de espera a la EDT, como ocurre por terminación normal.

Hay algunos más precisos análisis en cuando done es llamado en el caso de que un SwingWorker se cancela?

Aclaración:
esta pregunta es NO sobre cómo cancel un SwingWorker. Aquí se supone que la SwingWorker es cancelado en la forma correcta.

Y es NO acerca de hilo sigue trabajando, cuando se supone para ser terminado.

InformationsquelleAutor AgostinoX | 2011-06-01

6 Kommentare

  1. 19

    Cuando un hilo se cancela a través de

    myWorkerThread.cancel(true/false);

    el hecho es el método (sorprendentemente) llamado por el método cancel sí mismo.

    Lo que usted puede esperar que suceda, pero en realidad NO:

    – llamar a cancelar (ya sea con mayInterrupt o no)

    – cancelar configurar el hilo de cancelación

    – el doInBackground sale

    – el hecho se llama*

    (* el hecho es en la cola de espera a la EDT, que significa, que si EDT está ocupado ocurre DESPUÉS de la EDT ha terminado lo que está haciendo)

    Lo que en realidad sucede:

    – llamar a cancelar (ya sea con mayInterrupt o no)

    – cancelar configurar el hilo de cancelación

    – el hecho es llamado como parte de la cancelación de código*

    – el doInBackground va a salir cuando se haya terminado su bucle

    (*el hecho no está en la cola de espera para el EDT, pero el llamado a la cancelación de la llamada y por lo que tiene un efecto inmediato en la EDT, que a menudo es la interfaz gráfica de usuario)

    Me ofrecen un sencillo ejemplo que lo demuestra.

    Copiar, pegar y correr.

    1. Generar una excepción de tiempo de ejecución en el interior de hecho. La pila de rosca muestra que hace es llamado por cancelar.

    2. Después de 4 segundos después de la cancelación, usted recive un saludo desde el doInBackground, que fhurterly demuestra que el hecho se llama antes de que el hilo de salir.

    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!");}
    
    }
    
    }
    • +1 El mismo (sorprendente) resultado como llegué a la misma hora 😉
    • Así puede ocurrir, incluso, que publicar los resultados del proceso después de done.
    • tal vez este puede ayudarle a stackoverflow.com/questions/6113944/…
    • ¿a dónde vamos a partir de ahí? Dos problema que surge es: 1) ¿por qué es indocumentados 2) la cosa más importante. si al final el doInBackground libera recursos sensibles, ¿cómo estoy seguro de que ha terminado? Qué sugiere usted para abrir una nueva pregunta? (por favor, que es de lectura y no ha entendido exactamente esta sutil, este NO es el SwingWorker hilo de terminación ya se ha discutido en todas partes)
    • por favor, ver a mi pregunta stackoverflow.com/questions/7053865/…
    • Esto ha sido aceptado como un error por parte de Oracle: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514
    • gracias! esto es muy interesante, es en realidad este problema. Si yo hubiera sabido que en el momento en que puse esta pregunta, no hubiera sido todo este debate.
    • La documentación de SwingWorker sugerir que compruebe la isCancelled() para comprobar es el indicador de cancelar fue encendida por una llamada al método cancel. Así que supongo que su depende de usted. Si quita el sueño, los programas de terminar.. que significa que el doInBackground ejecutando todavía permanece como un ignorado hilo para el acabado. Todo el trabajo limpieza de la oscilación trabajador tiene que ir en el hecho de método.
    • Que informe de error no ha sido actualizado, pero en Java 7 llamadas #cancel() no llame #done() (Oracle JDK)
    • Lo siento, @searchengine27, pero ese no es el caso. Mirando el Java 8 JRE fuente de ahora; SwingWorker#cancel() llamadas FutureTask#cancel(), que si no regresa inmediatamente false llama a un método privado auxiliar finishCompletion(), que incondicionalmente llamadas FutureTask#done(). Y SwingWorker anónimo subclase de FutureTask invalida que done() para llamar a su propia SwingWorker#doneEDT(), que incondicionalmente llamadas o pone en cola de su propio done() en el EDT.

  2. 6

    done() se llama en cualquier caso, si el trabajador se cancela o termina normalmente. Sin embargo, hay casos donde la doInBackground todavía se está ejecutando y el done método se llama ya (esto se hace en el interior de cancel() no importa si el hilo ya terminado). Un simple ejemplo puede ser encontrado 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 que puede darse el caso de que done se llama antes de que doInBackground acabados.

    • Ok. el código es casi el mismo que he proporcionado. Más, me demostró que de hecho sucede en el interior de cancelar con el seguimiento de la pila de truco.
  3. 1

    algo es posible, otra podría ser la ilusión

    muy agradable de salida

    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)

    de

    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 ");
                }
            }
        }
    }
    • de trabajo en su muestra.La primera pregunta.Desde mi aplicación de SwingWorker métodos es de 6 filas, se puede señalar donde la «mala aplicación» es?Segundo.Nunca he usado «bug» de la palabra.Si usted lee la pregunta, verás que se trata de cuando la cancelación se llama.He demostrado más allá de cualquier duda de que sí, de hecho se llama en cada caso(en la EDT como era de esperar!) Y en el caso de cancelación no está en la cola de espera a EDT, sino que es necesaria como parte de la cancelación(…) la llamada,potencialmente, antes de salir de doInBackground método.Ahora estoy verificando el comportamiento exacto de PropertyChangeListener, voy a dejar que usted sabe.
    • Desde mi aplicación de SwingWorker métodos es de 6 filas 🙂 no, no es que simplemente vainilla innerClass o huecos 1er. de espera para el temporizador, 2do. para el 1er termina, nada esle, pequeño error…, vamos a volver a la salida (Coldplay), más importante si quieres jugar con SwingWorker, a continuación, el código podría ser para confirmar su salida directamente a la interfaz gráfica de usuario (JTextArea), de lo contrario no me hace sentido, porque el Sistema.a cabo.imprimir() funciona en todos los casos (+ – CitiBus), mucha suerte
    • Ok. así que la W de clase es el adecuado. ¿Te importaría quitar el comentario acerca de «mal implementación de clases»? Gracias. Entonces usted dice que el problema está a la espera para el temporizador? Que el temporizador? Tal vez te refieres al Hilo.el sueño. He hecho una clase que todo el mundo puede utilizar para reproducir el problema específico que estoy hablando, así que necesito algo que «cuelgan» de algunos segundos, como una lenta conexión de base de datos. Estoy seguro de que se puede hacer de mejor manera, así que me alegro de saber de usted.
    • seguro que voy a/puede quitar que sólo y únicamente por su preguntar, pero nada va a cambiar acerca de que la sintaxis correcta debe incluir extiende SwingWorker<Vacío, Vacío>/<Void, Cadena>/<Void, Double>…<Void, Icono de>, de lo contrario que no SwingWorker como sabíamos, sólo algunos de la clase que se requiere de algunos de los métodos, pero sin declarado SWingWorkers funcionalidades …, así que, finalmente, ahora que me voy de este hilo
    • por su pedirle demasiado, agregar <Vacío, Vacío> a mi SwingWorker aplicación, ya que ayudaría a la gente utiliza para ver los genéricos para entender bien la clase. Pero quiero pointout que él funcionalidades que no son proporcionados por los genéricos, sino por la ampliación de una clase o la implementación de una interfaz. Los medicamentos genéricos son una manera de evitar typecasts. Por otra parte, ya que son implementados por la cancelación, el código compilado con o sin es el mismo; estamos hablando de la conveniencia y hábitos, no la corrección.
  4. 1

    Hasta el SwingWorker se fija http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514
    Aquí, un simple (prueba) de la versión básica (similar) funciones 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();
            }
        }
    
    }
  5. 0

    De Java en google docs:
    cancelar(boolean mayInterruptIfRunning)
    «mayInterruptIfRunning – true si el subproceso que ejecuta esta tarea debe ser interrumpida; de lo contrario, en el progreso de las tareas se pueden completar»

    Si usted llame a cancelar(true) en lugar de cancelar la(falsa) que parece comportarse como usted está esperando.

    No he visto hacer() llama fuera de la EDT el uso de EventQueue.isDispatchThread()

  6. 0

    SI el uso de retorno Void: …@Override public Vacío doInBackground(){…

    hecho() se invoca cuando se doInBackground() ha terminado.

    SI no uso retorno Void: …@Override public booleano doInBackground(){…

    hecho() es ignorado y usted sabe que ha terminado causa tiene su devolución.

    • Bienvenido a ASÍ. Este post no cumple con nuestros estándares de calidad, cómo escribir una buena calidad de respuestas de lectura aquí.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea